diff --git a/ApiClient.js b/ApiClient.js index 2b282e5e42..49ce5fd959 100644 --- a/ApiClient.js +++ b/ApiClient.js @@ -441,7 +441,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi self.getLiveTvPrograms = function (options) { options = options || {}; - + if (options.channelIds && options.channelIds.length > 1800) { return self.ajax({ @@ -453,7 +453,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi }); } else { - + return self.ajax({ type: "GET", url: self.getUrl("LiveTv/Programs", options), @@ -666,6 +666,37 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi }); }; + self.getFileOrganizationResults = function (options) { + + var url = self.getUrl("Library/FileOrganization", options || {}); + + return self.ajax({ + type: "GET", + url: url, + dataType: "json" + }); + }; + + self.deleteOriginalFileFromOrganizationResult = function (id) { + + var url = self.getUrl("Library/FileOrganizations/" + id + "/File"); + + return self.ajax({ + type: "DELETE", + url: url + }); + }; + + self.performOrganization = function (id) { + + var url = self.getUrl("Library/FileOrganizations/" + id + "/Organize"); + + return self.ajax({ + type: "POST", + url: url + }); + }; + self.getLiveTvSeriesTimer = function (id) { if (!id) { @@ -4003,7 +4034,7 @@ MediaBrowser.ApiClient.create = function (clientName, applicationVersion) { var loc = window.location; var address = loc.protocol + '//' + loc.hostname; - + if (loc.port) { address += ':' + loc.port; } diff --git a/dashboard-ui/css/detailtable.css b/dashboard-ui/css/detailtable.css index c12e620fa6..c7920d5fdd 100644 --- a/dashboard-ui/css/detailtable.css +++ b/dashboard-ui/css/detailtable.css @@ -76,3 +76,10 @@ background-color: #eeeeee; /* non-RGBA fallback */ background-color: rgba(0,0,0,.1); } + + +.stripedTable tbody tr:nth-child(odd) td, +.stripedTable tbody tr:nth-child(odd) th { + background-color: #eeeeee; /* non-RGBA fallback */ + background-color: rgba(0,0,0,.04); +} diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css index f64002755d..eee3b1cd8c 100644 --- a/dashboard-ui/css/librarybrowser.css +++ b/dashboard-ui/css/librarybrowser.css @@ -171,7 +171,7 @@ } .labelPageSize { - margin-left: 1em; + margin-left: 1em!important; } diff --git a/dashboard-ui/css/site.css b/dashboard-ui/css/site.css index 64ffa009e0..4c04b96099 100644 --- a/dashboard-ui/css/site.css +++ b/dashboard-ui/css/site.css @@ -845,4 +845,13 @@ progress { .dashboardContent { max-width: 1100px; } +} + +.organizerButtonCell { + white-space: nowrap; +} + +.organizerButton { + margin-top: 0; + margin-bottom: 0; } \ No newline at end of file diff --git a/dashboard-ui/libraryfileorganizer.html b/dashboard-ui/libraryfileorganizer.html index d721b9b0c1..aeff074004 100644 --- a/dashboard-ui/libraryfileorganizer.html +++ b/dashboard-ui/libraryfileorganizer.html @@ -1,153 +1,145 @@  - Media Library + Auto-Organize -
+
-

File organizing allows the server to monitor your download folders for new files and move them to your media directories.

- - -
-

TV file organizing will only add episodes to existing series. It will not create new series folders.

-
    -
  • - - -
  • -
  • - -
    - -
    - -
    - The server will poll this folder during the "Organize new media files" scheduled task. -
    -
  • -
  • - - -
  • -
  • - - -
    -
  • -
  • - - -
  • -
-
-

Episode file pattern

-
-
-
- - -
-
- -

Supported Patterns

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TermPatternResult
Series Name%snSeries Name
Series Name%s.nSeries.Name
Series Name%s_nSeries_Name
Season Number%s1
Season Number%0s01
Episode Number%e4
Episode Number%0e04
Episode Name%enEpisode Name
Episode Name%e.nEpisode.Name
Episode Name%e_nEpisode_Name
+

The file organizer monitors your download folders for new files and moves them to your media directories.

+

TV file organizing will only add episodes to existing series. It will not create new series folders.

+
    +
  • + + +
  • +
  • + +
    +
    + +
    + The server will poll this folder during the "Organize new media files" scheduled task. +
    +
  • +
  • + + +
    Files under this size will be ignored.
    +
  • +
  • + + +
    +
  • +
  • + + +
  • +
+
+

Episode file pattern

+
+
+
+ + +
+
+ +

Supported Patterns

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TermPatternResult
Series Name%snSeries Name
Series Name%s.nSeries.Name
Series Name%s_nSeries_Name
Season Number%s1
Season Number%0s01
Episode Number%e4
Episode Number%0e04
Episode Name%enEpisode Name
Episode Name%e.nEpisode.Name
Episode Name%e_nEpisode_Name
+
-
-
    -
  • - - -
  • -
  • - - -
  • -
  • - - -
    With trial mode enabled, file organizations will be logged but not executed.
    -
  • -
+
+
    +
  • + + +
  • +
  • + + +
  • +
  • + + +
    With trial mode enabled, file organizations will be logged but not executed.
    +
  • +
  • diff --git a/dashboard-ui/libraryfileorganizerlog.html b/dashboard-ui/libraryfileorganizerlog.html new file mode 100644 index 0000000000..c10a3fadf0 --- /dev/null +++ b/dashboard-ui/libraryfileorganizerlog.html @@ -0,0 +1,41 @@ + + + + Auto-Organize + + +
    + +
    +
    + + + +
    +
    +
    +
    + + + + + + + + + + + + +
    DateSourceDestinationResult
    +
    +
    +
    +
    +
    +
    + + diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index 52c558197b..27029284fc 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -1426,7 +1426,7 @@ return html; }, - getPagingHtml: function (query, totalRecordCount, updatePageSizeSetting, pageSizes) { + getPagingHtml: function (query, totalRecordCount, updatePageSizeSetting, pageSizes, showLimit) { if (query.Limit && updatePageSizeSetting !== false) { localStorage.setItem('pagesize', query.Limit); @@ -1451,7 +1451,7 @@ var recordsEnd = Math.min(query.StartIndex + query.Limit, totalRecordCount); // 20 is the minimum page size - var showControls = totalRecordCount > 20; + var showControls = totalRecordCount > 20 || query.Limit < totalRecordCount; html += '
    '; @@ -1461,39 +1461,44 @@ html += startAtDisplay + '-' + recordsEnd + ' of ' + totalRecordCount; if (showControls) { - html += ', page ' + dropdownHtml + ' of ' + pageCount; + //html += ', page ' + dropdownHtml + ' of ' + pageCount; } html += ''; if (showControls) { + + html += '
    '; html += ''; html += ''; + html += '
    '; - var id = "selectPageSize" + new Date().getTime(); + if (showLimit !== false) { + var id = "selectPageSize" + new Date().getTime(); - var options = ''; + var options = ''; - function getOption(val) { + function getOption(val) { - if (query.Limit == val) { + if (query.Limit == val) { - return ''; + return ''; - } else { - return ''; + } else { + return ''; + } } + + pageSizes = pageSizes || [20, 50, 100, 200, 300, 400, 500]; + + for (var j = 0, length = pageSizes.length; j < length; j++) { + options += getOption(pageSizes[j]); + } + + // Add styles to defeat jquery mobile + html += ''; } - - pageSizes = pageSizes || [20, 50, 100, 200, 300, 400, 500]; - - for (var j = 0, length = pageSizes.length; j < length; j++) { - options += getOption(pageSizes[j]); - } - - // Add styles to defeat jquery mobile - html += ''; } html += '
    '; diff --git a/dashboard-ui/scripts/libraryfileorganizer.js b/dashboard-ui/scripts/libraryfileorganizer.js index 4148967bfe..911dfe5aea 100644 --- a/dashboard-ui/scripts/libraryfileorganizer.js +++ b/dashboard-ui/scripts/libraryfileorganizer.js @@ -52,13 +52,13 @@ var page = this; - $('#txtSeasonFolderPattern', page).on('change keypress', function() { + $('#txtSeasonFolderPattern', page).on('change keyup', function () { updateSeasonPatternHelp(page, this.value); }); - $('#txtEpisodePattern', page).on('change keypress', function () { + $('#txtEpisodePattern', page).on('change keyup', function () { updateEpisodePatternHelp(page, this.value); diff --git a/dashboard-ui/scripts/libraryfileorganizerlog.js b/dashboard-ui/scripts/libraryfileorganizerlog.js new file mode 100644 index 0000000000..0f2cd1b466 --- /dev/null +++ b/dashboard-ui/scripts/libraryfileorganizerlog.js @@ -0,0 +1,237 @@ +(function ($, document, window) { + + var query = { + + StartIndex: 0, + Limit: 50 + }; + + var currentResult; + + function showStatusMessage(id) { + + var item = currentResult.Items.filter(function (i) { + return i.Id == id; + + })[0]; + + Dashboard.alert({ + + title: getStatusText(item, false), + message: item.StatusMessage + + }); + } + + function deleteOriginalFile(page, id) { + + var item = currentResult.Items.filter(function (i) { + return i.Id == id; + + })[0]; + + var message = 'The following file will be deleted:

    ' + item.OriginalPath + '

    Are you sure you wish to proceed?

    '; + + Dashboard.confirm(message, "Delete File", function (confirmResult) { + + if (confirmResult) { + + Dashboard.showLoadingMsg(); + + ApiClient.deleteOriginalFileFromOrganizationResult(id).done(function () { + + Dashboard.hideLoadingMsg(); + + reloadItems(page); + + }); + } + + }); + } + + function organizeFile(page, id) { + + var item = currentResult.Items.filter(function (i) { + return i.Id == id; + + })[0]; + + var message = 'The following file will be moved from:

    ' + item.OriginalPath + '

    to:

    ' + item.TargetPath + '

    Are you sure you wish to proceed?

    '; + + Dashboard.confirm(message, "Organize File", function (confirmResult) { + + if (confirmResult) { + + Dashboard.showLoadingMsg(); + + ApiClient.performOrganization(id).done(function () { + + Dashboard.hideLoadingMsg(); + + reloadItems(page); + + }); + + } + + }); + + } + + function reloadItems(page) { + + Dashboard.showLoadingMsg(); + + ApiClient.getFileOrganizationResults(query).done(function (result) { + + currentResult = result; + renderResults(page, result); + + Dashboard.hideLoadingMsg(); + }); + + } + + function getStatusText(item, enhance) { + + var status = item.Status; + + var color = null; + + if (status == 'SkippedTrial') { + status = 'Trial'; + } + else if (status == 'SkippedExisting') { + status = 'Skipped'; + } + else if (status == 'Failure') { + color = '#cc0000'; + status = 'Failed'; + } + if (status == 'Success') { + color = 'green'; + status = 'Success'; + } + + if (enhance && enhance) { + + if (item.StatusMessage) { + + return '' + status + ''; + } else { + return '' + status + ''; + } + } + + + return status; + } + + function renderResults(page, result) { + + var rows = result.Items.map(function (item) { + + var html = ''; + + html += ''; + + html += ''; + + var date = parseISO8601Date(item.Date, { toLocal: true }); + html += date.toLocaleDateString(); + + html += ''; + + html += ''; + html += item.OriginalFileName || ''; + html += ''; + + html += ''; + html += item.TargetPath || ''; + html += ''; + + html += ''; + html += getStatusText(item, true); + html += ''; + + html += ''; + + + if (item.Status == 'SkippedTrial' || item.Status == 'SkippedExisting') { + html += ''; + } else { + html += ''; + } + + if (item.Status != 'Success') { + html += ''; + } + + html += ''; + + html += ''; + + return html; + }).join(''); + + var elem = $('.resultBody', page).html(rows).parents('.tblOrganizationResults').table("refresh").trigger('create'); + + $('.btnShowStatusMessage', elem).on('click', function () { + + var id = this.getAttribute('data-resultid'); + + showStatusMessage(id); + }); + + $('.btnProcessResult', elem).on('click', function () { + + var id = this.getAttribute('data-resultid'); + + organizeFile(page, id); + }); + + $('.btnDeleteResult', elem).on('click', function () { + + var id = this.getAttribute('data-resultid'); + + deleteOriginalFile(page, id); + }); + + var pagingHtml = LibraryBrowser.getPagingHtml(query, result.TotalRecordCount, false, [], false); + $('.listTopPaging', page).html(pagingHtml).trigger('create'); + + if (result.TotalRecordCount > query.Limit && result.TotalRecordCount > 50) { + $('.listBottomPaging', page).html(pagingHtml).trigger('create'); + } else { + $('.listBottomPaging', page).empty(); + } + + $('.selectPage', page).on('change', function () { + query.StartIndex = (parseInt(this.value) - 1) * query.Limit; + reloadItems(page); + }); + + $('.btnNextPage', page).on('click', function () { + query.StartIndex += query.Limit; + reloadItems(page); + }); + + $('.btnPreviousPage', page).on('click', function () { + query.StartIndex -= query.Limit; + reloadItems(page); + }); + } + + $(document).on('pageshow', "#libraryFileOrganizerLogPage", function () { + + var page = this; + + reloadItems(page); + + }).on('pagehide', "#libraryFileOrganizerLogPage", function () { + + currentResult = null; + }); + +})(jQuery, document, window); diff --git a/packages.config b/packages.config index 70c1bd6e29..3f77d9541e 100644 --- a/packages.config +++ b/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file