Skip to content

Commit

Permalink
[39] Allow importing Cards to a Series via batch upload
Browse files Browse the repository at this point in the history
Implements #449
  • Loading branch information
CollinHeist committed Mar 19, 2024
1 parent 7ad49b9 commit e7c178a
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 25 deletions.
121 changes: 97 additions & 24 deletions app/templates/js/series.js
Original file line number Diff line number Diff line change
Expand Up @@ -1159,7 +1159,7 @@ async function initAll() {
// Reload image
$('#poster-image')[0].src = `${response}?${new Date().getTime()}`;
},
error: response => showErrorToast({title: 'Error updating poster', response}),
error: response => showErrorToast({title: 'Error updating poster', response}),
complete: () => setTimeout(() => $('#submit-poster-button').toggleClass('loading', false), 750),
});
});
Expand Down Expand Up @@ -2192,33 +2192,106 @@ function removePlexLabels(interfaceId, libraryName) {
}

/**
* Add a blank Series Extra field to the card configuration form.
* @type {File[]}
*/
function addBlankSeriesExtra() {
const newExtra = document.getElementById('extra-template').content.cloneNode(true);
$('#card-config-form .field[data-value="extras"]').append(newExtra);
initializeExtraDropdowns(
null,
$(`#card-config-form .dropdown[data-value="extra_keys"]`).last(),
$(`#card-config-form .popup .header`).last(),
$(`#card-config-form .popup .description`).last(),
);
refreshTheme();
$('#card-config-form .field[data-value="extras"] .link.icon').popup({inline: true});
let pendingFiles = [];
function showCardUpload() {
$('#upload-cards-modal table').css('display', 'none');
$('#upload-cards-modal table tbody tr').remove();
$('#upload-cards-modal').modal('show');
pendingFiles = [];
}

/**
* Add a blank Episode Extra field to the Episode extra modal form.
*
* @param {DragEvent} event
*/
function addBlankEpisodeExtra() {
const newExtra = document.getElementById('extra-template').content.cloneNode(true);
$('#episode-extras-modal .field[data-value="extras"]').append(newExtra);
initializeExtraDropdowns(
null,
$(`#episode-extras-modal .dropdown[data-value="extra_keys"]`).last(),
$(`#episode-extras-modal .field[data-value="extras"] .popup .header`).last(),
$(`#episode-extras-modal .field[data-value="extras"] .popup .description`).last(),
);
function dropHandler(event) {
// Prevent default behavior (Prevent file from being opened)
ev.preventDefault();

/**
* Parse the season and episode number from the given string (filename).
* @param {string} name - Name of the file being parsed for indices.
* @returns {?[number, number]} Array of the season and episode number parsed
* from the given name.
*/
const parseFilename = (name) => name.match(/.*s(\d+).*e(\d+)/i)?.slice(1).map(Number);

/**
*
* @param {File} file - File to create an entry out of.
*/
const newFile = (file) => {
// Fill out row
const table = document.querySelector('#upload-cards-modal table tbody');
const newRow = document.getElementById('file-upload-template').content.cloneNode(true);

// Populate file name; when clicked, remove from table and file list
newRow.querySelector('[data-row="file"] a').innerText = file.name;
newRow.querySelector('[data-row="file"] a').onclick = () => {
pendingFiles = pendingFiles.filter(thisFile => thisFile.name !== file.name);
$(`#upload-cards-modal tr[data-filename="${file.name}"]`).remove();
}
// Add file name to dataset so CSS query works
newRow.querySelector('tr').dataset.filename = file.name;

// Try and parse season and episode indices from filename
const indices = parseFilename(file.name);
if (indices) {
newRow.querySelector('[data-row="season"]').innerText = indices[0];
newRow.querySelector('[data-row="episode"]').innerText = indices[1];
pendingFiles.push(file);
} else {
// Cannot parse; mark row as error
newRow.querySelector('tr').className = 'error';
newRow.querySelector('[data-row="season"]').innerText = 'Cannot Determine';
newRow.querySelector('[data-row="episode"]').innerText = 'Cannot Determine';
}
table.appendChild(newRow);
}
$('#upload-cards-modal table').css('display', 'table');

// Iterate through all uploaded files, add a table row for each valid upload
[...event.dataTransfer.items || event.dataTransfer.files].forEach((item) => {
if (item.kind === 'file' && item.type !== '') {
newFile(item.getAsFile() || item);
}
});
refreshTheme();
$('#episode-extras-modal .field[data-value="extras"] .link.icon').popup({inline: true});
}

/**
* Submit an API request to upload and import the cards which are currently
* loaded. After the request is finished, all series-data is re-queried.
*/
function uploadCards() {
// No files uploaded, exit
if (pendingFiles.length === 0) {
showInfoToast('No Cards to Upload');
return;
}

// Add files to FormData object
const f = new FormData();
pendingFiles.forEach(file => f.append('cards', file));

// Submit API request
$.ajax({
type: 'POST',
url: '/api/import/series/{{series.id}}/cards',
data: f,
cache: false,
contentType: false,
processData: false,
/** Cards uploaded and imported. Show success toast. */
success: () => showInfoToast('Title Cards Uploaded and Imported'),
error: response => showErrorToast({title: 'Error Uploading Cards', response}),
/** Re-query statistics, card data, and file data */
complete: () => {
getStatistics();
getCardData();
getFileData();
}
});
}
39 changes: 39 additions & 0 deletions app/templates/series.html
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,14 @@ <h3>Season {x} Episode {y}</h3>
<p class="help">{tooltip}</p>
</div>
</template>

<template id="file-upload-template">
<tr>
<td class="selectable" data-row="file"><a></a></td>
<td data-row="season"></td>
<td data-row="episode"></td>
</tr>
</template>
</head>

<body onload="initAll()">
Expand Down Expand Up @@ -1410,6 +1418,37 @@ <h2 class="ui dividing header">Backdrop</h2>
</div>
</div>

<div id="upload-cards-modal" class="ui small modal" ondragover="event.preventDefault();" ondrop="dropHandler(event);">
<div class="center aligned header">Upload Title Cards</div>
<div class="center aligned scrolling content" >
<input type="file" name="cards[]" multiple id="card-upload" class="ui invisible file input" data-multiple-caption="{count} files selected">
<label for="card-upload" class="ui placeholder segment">
<div class="ui icon header">
<i class="upload icon"></i>
Drag Files
<br>
or
<br>
Click here to upload
</div>
</label>
<table class="ui striped table">
<thead>
<tr>
<th>File</th>
<th>Season</th>
<th>Episode</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div class="center aligned actions">
<div class="ui negative button">Cancel</div>
<div class="ui positive button" onclick="uploadCards();">OK</div>
</div>
</div>

<!-- Season title helper popup -->
<div id="season-title-popup" class="ui flowing uninvertible popup right">
<div class="ui list content">
Expand Down
2 changes: 1 addition & 1 deletion modules/ref/version_webui
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v2.0-alpha.9.0-webui38
v2.0-alpha.9.0-webui39

0 comments on commit e7c178a

Please sign in to comment.