1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

move recording editor to popup

This commit is contained in:
Luke Pulverenti 2016-05-09 23:36:43 -04:00
parent 25f06c166b
commit 4d7b51f730
19 changed files with 322 additions and 248 deletions

View file

@ -143,6 +143,7 @@ See [iron-iconset](#iron-iconset) and [iron-iconset-svg](#iron-iconset-svg) for
<g id="notifications-off"><path d="M11.5 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zM18 10.5c0-3.07-2.13-5.64-5-6.32V3.5c0-.83-.67-1.5-1.5-1.5S10 2.67 10 3.5v.68c-.51.12-.99.32-1.45.56L18 14.18V10.5zm-.27 8.5l2 2L21 19.73 4.27 3 3 4.27l2.92 2.92C5.34 8.16 5 9.29 5 10.5V16l-2 2v1h14.73z" /></g>
<g id="expand-less"><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z" /></g>
<g id="expand-more"><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" /></g>
<g id="fiber-smart-record"><g><circle cx="9" cy="12" r="8" /><path d="M17 4.26v2.09c2.33.82 4 3.04 4 5.65s-1.67 4.83-4 5.65v2.09c3.45-.89 6-4.01 6-7.74s-2.55-6.85-6-7.74z" /></g></g>
</defs>
</svg>
</iron-iconset-svg>

View file

@ -16,12 +16,12 @@
},
"devDependencies": {},
"ignore": [],
"version": "1.2.67",
"_release": "1.2.67",
"version": "1.2.70",
"_release": "1.2.70",
"_resolution": {
"type": "version",
"tag": "1.2.67",
"commit": "47093f0f441935b5ccc02999f1981e2e274fb1dc"
"tag": "1.2.70",
"commit": "da1751d5ebd43e4681ef9a0834e08d094505e725"
},
"_source": "https://github.com/MediaBrowser/emby-webcomponents.git",
"_target": "^1.2.0",

View file

@ -150,11 +150,7 @@
// The dialog may have just been created and webComponents may not have completed initialiazation yet.
// Without this, seeing some script errors in Firefox
var delay = browser.animate ? 0 : 500;
if (!delay) {
focusManager.autoFocus(dlg);
return;
}
var delay = browser.animate ? 200 : 500;
setTimeout(function () {
focusManager.autoFocus(dlg);
@ -324,8 +320,12 @@
// Also not working well in samsung tizen browser, content inside not clickable
if (!dlg.showModal || browser.tv) {
dlg = document.createElement('div');
} else {
// Just go ahead and always use a plain div because we're seeing issues overlaying absoltutely positioned content over a modal dialog
dlg = document.createElement('div');
}
dlg.classList.add('focuscontainer');
dlg.classList.add('hide');
if (shouldLockDocumentScroll(options)) {

View file

@ -21,7 +21,7 @@ define([], function () {
function focus(element) {
var tagName = element.tagName;
if (tagName == 'PAPER-INPUT' || tagName == 'PAPER-DROPDOWN-MENU' || tagName == 'EMBY-DROPDOWN-MENU') {
if (tagName == 'PAPER-INPUT' || tagName == 'EMBY-DROPDOWN-MENU') {
element = element.querySelector('input') || element;
}
@ -32,8 +32,8 @@ define([], function () {
}
}
var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A', 'PAPER-BUTTON', 'PAPER-INPUT', 'PAPER-TEXTAREA', 'PAPER-ICON-BUTTON', 'PAPER-FAB', 'PAPER-CHECKBOX', 'PAPER-ICON-ITEM', 'PAPER-MENU-ITEM', 'PAPER-DROPDOWN-MENU', 'EMBY-DROPDOWN-MENU'];
var focusableContainerTagNames = ['BODY', 'PAPER-DIALOG', 'DIALOG'];
var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A', 'PAPER-BUTTON', 'PAPER-INPUT', 'PAPER-TEXTAREA', 'PAPER-FAB', 'PAPER-CHECKBOX', 'PAPER-ICON-ITEM', 'PAPER-MENU-ITEM', 'EMBY-DROPDOWN-MENU'];
var focusableContainerTagNames = ['BODY', 'DIALOG'];
var focusableQuery = focusableTagNames.join(',') + ',.focusable';
function isFocusable(elem) {
@ -102,6 +102,9 @@ define([], function () {
if (focusableContainerTagNames.indexOf(elem.tagName) != -1) {
return true;
}
if (elem.classList.contains('focuscontainer')) {
return true;
}
if (direction < 2) {
if (elem.classList.contains('focuscontainer-x')) {

View file

@ -28,14 +28,14 @@
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
},
"ignore": [],
"homepage": "https://github.com/polymerelements/iron-resizable-behavior",
"homepage": "https://github.com/PolymerElements/iron-resizable-behavior",
"_release": "1.0.3",
"_resolution": {
"type": "version",
"tag": "v1.0.3",
"commit": "dda1df6aaf452aedf3e52ff0cf69e72439452216"
},
"_source": "git://github.com/polymerelements/iron-resizable-behavior.git",
"_source": "git://github.com/PolymerElements/iron-resizable-behavior.git",
"_target": "^1.0.0",
"_originalSource": "polymerelements/iron-resizable-behavior"
"_originalSource": "PolymerElements/iron-resizable-behavior"
}

View file

@ -34,6 +34,6 @@
"commit": "11c987b2eb3c73b388a79fc8aaea8ca01624f514"
},
"_source": "git://github.com/Polymer/polymer.git",
"_target": "^1.1.0",
"_target": "^1.0.0",
"_originalSource": "Polymer/polymer"
}

View file

@ -0,0 +1,163 @@
define(['dialogHelper', 'loading', 'jQuery', 'paper-checkbox', 'paper-input', 'emby-collapsible', 'paper-button', 'paper-icon-button-light'], function (dialogHelper, loading, $) {
var currentDialog;
var recordingUpdated = false;
var currentItemId;
function renderTimer(context, item) {
var programInfo = item.ProgramInfo || {};
$('.itemName', context).html(item.Name);
$('.itemEpisodeName', context).html(programInfo.EpisodeTitle || '');
$('.itemCommunityRating', context).html(LibraryBrowser.getRatingHtml(programInfo));
LibraryBrowser.renderGenres($('.itemGenres', context), programInfo);
LibraryBrowser.renderOverview(context.querySelectorAll('.itemOverview'), programInfo);
if (programInfo.ImageTags && programInfo.ImageTags.Primary) {
var imgUrl = ApiClient.getScaledImageUrl(programInfo.Id, {
maxWidth: 200,
maxHeight: 200,
tag: programInfo.ImageTags.Primary,
type: "Primary"
});
$('.timerPageImageContainer', context).css("display", "inline-block")
.html('<img src="' + imgUrl + '" style="max-width:200px;max-height:200px;" />');
} else {
$('.timerPageImageContainer', context).hide();
}
$('.itemMiscInfo', context).html(LibraryBrowser.getMiscInfoHtml(programInfo));
$('#txtPrePaddingMinutes', context).val(item.PrePaddingSeconds / 60);
$('#txtPostPaddingMinutes', context).val(item.PostPaddingSeconds / 60);
if (item.Status == 'New') {
$('.timerStatus', context).hide();
} else {
$('.timerStatus', context).show().html('Status:&nbsp;&nbsp;&nbsp;' + item.Status);
}
loading.hide();
}
function closeDialog(isSubmitted) {
recordingUpdated = isSubmitted;
dialogHelper.close(currentDialog);
}
function onSubmit(e) {
loading.show();
var form = this;
ApiClient.getLiveTvTimer(currentItemId).then(function (item) {
item.PrePaddingSeconds = $('#txtPrePaddingMinutes', form).val() * 60;
item.PostPaddingSeconds = $('#txtPostPaddingMinutes', form).val() * 60;
ApiClient.updateLiveTvTimer(item).then(function () {
loading.hide();
require(['toast'], function (toast) {
toast(Globalize.translate('MessageRecordingSaved'));
closeDialog(true);
});
});
});
e.preventDefault();
// Disable default form submission
return false;
}
function init(context) {
context.querySelector('.btnCancel').addEventListener('click', function () {
closeDialog(false);
});
context.querySelector('form').addEventListener('submit', onSubmit);
context.querySelector('.btnHeaderSave').addEventListener('click', function (e) {
context.querySelector('.btnSave').click();
});
}
function reload(context, id) {
loading.show();
currentItemId = id;
ApiClient.getLiveTvTimer(id).then(function (result) {
renderTimer(context, result);
loading.hide();
});
}
function showEditor(itemId) {
return new Promise(function (resolve, reject) {
recordingUpdated = false;
loading.show();
var xhr = new XMLHttpRequest();
xhr.open('GET', 'components/recordingeditor/recordingeditor.template.html', true);
xhr.onload = function (e) {
var template = this.response;
var dlg = dialogHelper.createDialog({
removeOnClose: true,
size: 'small'
});
dlg.classList.add('ui-body-b');
dlg.classList.add('background-theme-b');
dlg.classList.add('formDialog');
var html = '';
html += Globalize.translateDocument(template);
dlg.innerHTML = html;
document.body.appendChild(dlg);
dialogHelper.open(dlg);
currentDialog = dlg;
dlg.addEventListener('close', function () {
if (recordingUpdated) {
resolve();
} else {
reject();
}
});
init(dlg);
reload(dlg, itemId);
}
xhr.send();
});
}
return {
show: showEditor
};
});

View file

@ -0,0 +1,55 @@
<div class="dialogHeader">
<button is="paper-icon-button-light" class="btnCancel" tabindex="-1"><iron-icon icon="arrow-back"></iron-icon></button>
<div class="dialogHeaderTitle">
${ButtonEdit}
</div>
<div style="margin-left:auto; display: flex; align-items: center; justify-content: center;">
<paper-button class="btnHeaderSave accent" tabindex="-1">
<iron-icon icon="check"></iron-icon>
<span>${ButtonSave}</span>
</paper-button>
</div>
</div>
<div class="readOnlyContent" style="margin: 0 auto;">
<div>
<div style="display: none; vertical-align: top; margin-right: 1em; padding-top: 1em;" class="timerPageImageContainer">
</div>
<div style="display: inline-block; vertical-align: middle;">
<p><span class="itemName inlineItemName"></span></p>
<p class="itemEpisodeName"></p>
<p class="itemMiscInfo miscTvProgramInfo"></p>
<p>
<span class="itemCommunityRating"></span>
</p>
<p class="itemGenres"></p>
</div>
</div>
<p class="itemOverview smoothScrollY"></p>
<p style="margin-top: 2em;" class="timerStatus">
</p>
</div>
<br />
<form class="liveTvTimerForm" style="margin: 0 auto;">
<h1>${HeaderRecordingOptions}</h1>
<emby-collapsible title="${HeaderAdvanced}">
<br />
<div>
<paper-input type="number" id="txtPrePaddingMinutes" pattern="[0-9]*" required="required" min="0" step="1" label="${LabelPrePaddingMinutes}"></paper-input>
</div>
<br />
<div>
<paper-input type="number" id="txtPostPaddingMinutes" pattern="[0-9]*" required="required" min="0" step="1" label="${LabelPostPaddingMinutes}"></paper-input>
</div>
<br />
</emby-collapsible>
<br />
<br />
<div>
<button type="submit" data-role="none" class="clearButton btnSave">
<paper-button raised class="submit block"><iron-icon icon="check"></iron-icon><span>${ButtonSave}</span></paper-button>
</button>
</div>
</form>

View file

@ -1033,6 +1033,13 @@ span.itemCommunityRating:not(:empty) + .userDataIcons {
background-color: #52B54B;
}
.seriesTimerIndicator {
color: #cc3333;
position: absolute;
top: 5px;
right: 5px;
}
.playedIndicator + .syncIndicator {
top: 32px;
}

View file

@ -204,7 +204,7 @@
.libraryViewNav .mdl-tabs__tab {
color: #888 !important;
color: #aaa !important;
padding: 0 1.25em;
float: none;
flex-shrink: 0;
@ -500,22 +500,6 @@ body:not(.dashboardDocument) .btnNotifications {
color: #fff !important;
}
.adminDrawerPanel #drawer .emby-collapsible-button {
padding-top: 0;
padding-bottom: 0;
padding-left: 1em;
}
.adminDrawerPanel #drawer .emby-collapsible-title {
font-size: inherit;
text-transform: none;
margin: .7em 0;
}
.adminDrawerPanel #drawer #expandButton {
color: #333;
}
.adminDrawerLogo {
padding: 1.5em 1em 1.2em;
border-bottom: 1px solid #e0e0e0;

View file

@ -1554,3 +1554,23 @@ emby-collapsible > .style-scope {
padding: 1em 1.25em;
background-color: #fff;
}
.ui-body-b .emby-collapsible-button {
border: 1px solid #222;
background-color: #444;
text-transform: none;
}
.ui-body-b .emby-collapsible-title {
margin: .25em 0;
color: #fff;
padding: 0 0 0 .5em;
font-weight: 500;
}
.ui-body-b .emby-collapsible-content {
border: 1px solid #222;
border-width: 0 1px 1px 1px;
padding: 1em 1.25em;
background-color: #333;
}

View file

@ -1,7 +1,8 @@
<div id="liveTvSeriesTimerPage" data-role="page" class="page libraryPage liveTvPage noSecondaryNavPage" data-contextname="${HeaderLiveTv}" data-require="jqmcheckbox,jqmcontrolgroup,paper-button,jqmcollapsible,scripts/livetvcomponents,scripts/livetvseriestimer,livetvcss,paper-checkbox,paper-input" data-backbutton="true" data-menubutton="false">
<div data-role="content">
<form class="liveTvSeriesTimerForm" style="margin: 0 auto; max-width: 720px;">
<div class="readOnlyContent" style="margin:auto; max-width: 720px;">
<p><span class="itemName inlineItemName"></span></p>
<p class="channel" style="margin-top: 2em;"></p>
@ -11,13 +12,15 @@
<div data-role="controlgroup" data-type="horizontal" data-mini="true" class="seriesTimerTabs">
<input type="radio" name="radioSeriesTimerTab" class="radioSeriesTimerTab" id="radioSettings" value="settings">
<label for="radioSettings">${TabSettings}</label>
<input type="radio" name="radioSeriesTimerTab" class="radioSeriesTimerTab" id="radioRecordings" value="recordings">
<label for="radioRecordings">${TabRecordings}</label>
<input type="radio" name="radioSeriesTimerTab" class="radioSeriesTimerTab" id="radioScheduled" value="schedule">
<label for="radioScheduled">${TabScheduled}</label>
<label for="radioScheduled">${TabRecordings}</label>
</div>
<div style="clear:both;"></div>
</div>
<br />
<div class="settingsTab tab">
<form class="liveTvSeriesTimerForm" style="margin: 0 auto; max-width: 720px;">
<div>
<h1>${HeaderDays}</h1>
</div>
@ -61,10 +64,10 @@
<paper-button raised class="cancel block btnCancel" onclick="history.back();"><iron-icon icon="close"></iron-icon><span>${ButtonCancel}</span></paper-button>
</div>
</div>
<div class="recordingsTab tab"></div>
<div class="scheduleTab tab"></div>
</form>
</div>
<div class="scheduleTab tab"></div>
</div>
</div>

View file

@ -1,57 +0,0 @@
<div id="liveTvTimerPage" data-role="page" class="page libraryPage liveTvPage noSecondaryNavPage" data-contextname="${HeaderLiveTv}" data-require="jqmcollapsible,scripts/livetvcomponents,scripts/livetvtimer,livetvcss,paper-input,paper-button" data-backbutton="true" data-menubutton="false">
<div data-role="content">
<div class="readOnlyContent" style="margin: 0 auto;">
<div>
<div style="display: none; vertical-align: top; margin-right: 1em; padding-top: 1em;" class="timerPageImageContainer">
</div>
<div style="display: inline-block; vertical-align: middle;">
<p><span class="itemName inlineItemName"></span></p>
<p class="itemEpisodeName"></p>
<p class="itemMiscInfo miscTvProgramInfo"></p>
<p>
<span class="itemCommunityRating"></span>
</p>
<p class="itemGenres"></p>
</div>
</div>
<p class="itemOverview smoothScrollY"></p>
<p style="margin-top: 2em;" class="timerStatus">
</p>
<div style="margin-top: 2em;">
<paper-button class="subdued" raised id="btnCancelTimer"><iron-icon icon="delete"></iron-icon><span>${ButtonCancelRecording}</span></paper-button>
</div>
</div>
<br />
<form class="liveTvTimerForm" style="margin: 0 auto;">
<h1>${HeaderRecordingOptions}</h1>
<div data-role="collapsible" data-mini="true">
<h3>${HeaderAdvanced}</h3>
<div>
<br />
<div>
<paper-input type="number" id="txtPrePaddingMinutes" pattern="[0-9]*" required="required" min="0" step="1" label="${LabelPrePaddingMinutes}"></paper-input>
</div>
<br />
<div>
<paper-input type="number" id="txtPostPaddingMinutes" pattern="[0-9]*" required="required" min="0" step="1" label="${LabelPostPaddingMinutes}"></paper-input>
</div>
<br />
</div>
</div>
<br />
<br />
<div>
<button type="submit" data-role="none" class="clearButton">
<paper-button raised class="submit block"><iron-icon icon="check"></iron-icon><span>${ButtonSave}</span></paper-button>
</button>
<paper-button raised class="cancel block btnCancel" onclick="history.back();"><iron-icon icon="close"></iron-icon><span>${ButtonCancel}</span></paper-button>
</div>
</form>
</div>
</div>

View file

@ -2051,7 +2051,7 @@
Dashboard.getCurrentUser().then(function (user) {
LibraryBrowser.showMoreCommands(button, currentItem.Id, LibraryBrowser.getMoreCommands(currentItem, user));
LibraryBrowser.showMoreCommands(button, currentItem.Id, currentItem.Type, LibraryBrowser.getMoreCommands(currentItem, user));
});
});

View file

@ -776,7 +776,15 @@
});
},
showMoreCommands: function (positionTo, itemId, commands) {
editTimer: function (id) {
require(['components/recordingeditor/recordingeditor'], function (recordingeditor) {
recordingeditor.show(id);
});
},
showMoreCommands: function (positionTo, itemId, itemType, commands) {
var items = [];
@ -913,7 +921,11 @@
break;
}
case 'edit':
if (itemType == 'Timer') {
LibraryBrowser.editTimer(itemId);
} else {
LibraryBrowser.editMetadata(itemId);
}
break;
case 'editsubtitles':
LibraryBrowser.editSubtitles(itemId);
@ -1049,9 +1061,6 @@
return "itemdetails.html?id=" + id;
}
if (item.Type == "Timer") {
return "livetvtimer.html?id=" + id;
}
if (item.Type == "BoxSet") {
return "itemdetails.html?id=" + id;
}
@ -2195,6 +2204,10 @@
html += LibraryBrowser.getGroupCountIndicator(item);
}
if (item.SeriesTimerId) {
html += '<iron-icon icon="fiber-smart-record" class="seriesTimerIndicator"></iron-icon>';
}
html += LibraryBrowser.getSyncIndicator(item);
if (mediaSourceCount > 1) {
@ -3470,9 +3483,9 @@
else if (item.TimerId) {
var html = '';
html += '<a href="livetvtimer.html?id=' + item.TimerId + '">';
html += '<button type="button" class="clearButton" onclick="LibraryBrowser.editTimer(\'' + item.TimerId + '\');">';
html += '<div class="timerCircle"></div>';
html += '</a>';
html += '</button>';
miscInfo.push(html);
require(['livetvcss']);
}

View file

@ -532,7 +532,11 @@
break;
}
case 'edit':
if (itemType == 'Timer') {
LibraryBrowser.editTimer(itemId);
} else {
LibraryBrowser.editMetadata(itemId);
}
break;
case 'refresh':
ApiClient.refreshItem(itemId, {
@ -555,7 +559,11 @@
MediaController.shuffle(itemId);
break;
case 'open':
if (itemType == 'Timer') {
LibraryBrowser.editTimer(itemId);
} else {
Dashboard.navigate(href);
}
break;
case 'album':
Dashboard.navigate('itemdetails.html?id=' + albumid);
@ -1378,6 +1386,15 @@
MediaController.instantMix(itemId);
}
else if (action == 'edit') {
var itemType = elemWithAttributes.getAttribute('data-itemtype');
if (itemType == 'Timer') {
LibraryBrowser.editTimer(itemId);
} else {
LibraryBrowser.editMetadata(itemId);
}
}
e.stopPropagation();
e.preventDefault();

View file

@ -74,7 +74,8 @@
showChannelName: true,
lazy: true,
cardLayout: true,
showDetailsMenu: true
showDetailsMenu: true,
defaultAction: 'edit'
});
html += '</div>';

View file

@ -1,130 +0,0 @@
define(['jQuery'], function ($) {
var currentItem;
function deleteTimer(page, id) {
require(['confirm'], function (confirm) {
confirm(Globalize.translate('MessageConfirmRecordingCancellation'), Globalize.translate('HeaderConfirmRecordingCancellation')).then(function () {
Dashboard.showLoadingMsg();
ApiClient.cancelLiveTvTimer(id).then(function () {
require(['toast'], function (toast) {
toast(Globalize.translate('MessageRecordingCancelled'));
});
Dashboard.navigate('livetv.html');
});
});
});
}
function renderTimer(page, item) {
currentItem = item;
var programInfo = item.ProgramInfo || {};
$('.itemName', page).html(item.Name);
$('.itemEpisodeName', page).html(programInfo.EpisodeTitle || '');
$('.itemCommunityRating', page).html(LibraryBrowser.getRatingHtml(programInfo));
LibraryBrowser.renderGenres($('.itemGenres', page), programInfo);
LibraryBrowser.renderOverview(page.querySelectorAll('.itemOverview'), programInfo);
if (programInfo.ImageTags && programInfo.ImageTags.Primary) {
var imgUrl = ApiClient.getScaledImageUrl(programInfo.Id, {
maxWidth: 200,
maxHeight: 200,
tag: programInfo.ImageTags.Primary,
type: "Primary"
});
$('.timerPageImageContainer', page).css("display", "inline-block")
.html('<img src="' + imgUrl + '" style="max-width:200px;max-height:200px;" />');
} else {
$('.timerPageImageContainer', page).hide();
}
$('.itemMiscInfo', page).html(LibraryBrowser.getMiscInfoHtml(programInfo));
$('#txtPrePaddingMinutes', page).val(item.PrePaddingSeconds / 60);
$('#txtPostPaddingMinutes', page).val(item.PostPaddingSeconds / 60);
if (item.Status == 'New') {
$('.timerStatus', page).hide();
} else {
$('.timerStatus', page).show().html('Status:&nbsp;&nbsp;&nbsp;' + item.Status);
}
Dashboard.hideLoadingMsg();
}
function onSubmit() {
Dashboard.showLoadingMsg();
var form = this;
ApiClient.getLiveTvTimer(currentItem.Id).then(function (item) {
item.PrePaddingSeconds = $('#txtPrePaddingMinutes', form).val() * 60;
item.PostPaddingSeconds = $('#txtPostPaddingMinutes', form).val() * 60;
ApiClient.updateLiveTvTimer(item).then(function () {
Dashboard.hideLoadingMsg();
require(['toast'], function (toast) {
toast(Globalize.translate('MessageRecordingSaved'));
});
});
});
// Disable default form submission
return false;
}
function reload(page) {
Dashboard.showLoadingMsg();
var id = getParameterByName('id');
ApiClient.getLiveTvTimer(id).then(function (result) {
renderTimer(page, result);
});
}
$(document).on('pageinit', "#liveTvTimerPage", function () {
var page = this;
$('#btnCancelTimer', page).on('click', function () {
deleteTimer(page, currentItem.Id);
});
$('.liveTvTimerForm').off('submit', onSubmit).on('submit', onSubmit);
}).on('pagebeforeshow', "#liveTvTimerPage", function () {
var page = this;
reload(page);
}).on('pagebeforehide', "#liveTvTimerPage", function () {
currentItem = null;
});
});

View file

@ -2628,12 +2628,6 @@ var AppInfo = {};
roles: 'admin'
});
defineRoute({
path: '/livetvtimer.html',
dependencies: ['scrollStyles'],
autoFocus: false
});
defineRoute({
path: '/livetvtunerprovider-hdhomerun.html',
dependencies: [],