You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
6.4 KiB
233 lines
6.4 KiB
/* |
|
* This file is part of video_metadata. |
|
* |
|
* video_metadata is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation, either version 3 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* video_metadata is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with video_metadata. If not, see <https://www.gnu.org/licenses/>. |
|
*/ |
|
|
|
|
|
const SCAN_URL = 'admin.php?action=scan'; |
|
const VERIFY_URL = 'admin.php?action=verify'; |
|
|
|
|
|
function copyJSONtoDOMData(node, path_info) |
|
{ |
|
node.dataset.baseName = path_info.base_name; |
|
node.dataset.contentSize = path_info.content_size; |
|
node.dataset.depth = path_info.depth; |
|
node.dataset.fileExtension = path_info.path_extension; |
|
node.dataset.fullPath = path_info.full_path; |
|
node.dataset.mediaType = path_info.media_type; |
|
node.dataset.pathType = path_info.path_type; |
|
} |
|
|
|
function updatePathInfoStyle(node) |
|
{ |
|
node.classList.remove('unknown', 'movie', 'tv_show'); |
|
|
|
if (node.dataset.pathType == 'directory') { |
|
node.classList.add('directory'); |
|
} else if (node.dataset.pathType == 'file') { |
|
node.classList.add('file'); |
|
|
|
if (node.dataset.mediaType != '') |
|
node.classList.add(node.dataset.mediaType); |
|
} |
|
|
|
if (node.dataset.mediaType == 'unknown') |
|
node.classList.add('unknown'); |
|
} |
|
|
|
function updateMediaType(node, media_type) |
|
{ |
|
node.dataset.mediaType = media_type; |
|
updateRadioButtons(node, media_type) |
|
updatePathInfoStyle(node); |
|
|
|
for (let child of node.children) { |
|
if (child.nodeName == 'DIV') |
|
updateMediaType(child, media_type); |
|
} |
|
} |
|
|
|
function updateRadioButtons(node, media_type) |
|
{ |
|
if (media_type == 'movie') { |
|
node.querySelector('input[value^="tv_show"]').setAttribute('checked', false); |
|
node.querySelector('input[value^="movie"]').setAttribute('checked', true); |
|
} else if (media_type == 'tv_show') { |
|
node.querySelector('input[value^="movie"]').setAttribute('checked', false); |
|
node.querySelector('input[value^="tv_show"]').setAttribute('checked', true); |
|
} |
|
} |
|
|
|
// NOTE: recursively build DOM tree with attached data attributes and callbacks |
|
// for editing the data |
|
function buildDirectoryTreeWithData(path_info) |
|
{ |
|
const DEPTH_NAMES = ['depth_0', 'depth_1', 'depth_2', 'depth_3', 'depth_4', 'depth_5']; |
|
|
|
let t = document.querySelector("#path_info_template"); |
|
let clone = document.importNode(t.content, true); |
|
let sub_list = clone.querySelector('div'); |
|
sub_list.querySelector('form span').textContent = path_info.base_name; |
|
sub_list.classList.add(DEPTH_NAMES[path_info.depth]); |
|
|
|
copyJSONtoDOMData(sub_list, path_info); |
|
updatePathInfoStyle(sub_list); |
|
updateRadioButtons(sub_list, path_info.media_type) |
|
|
|
// NOTE: don't display the radio buttons on top level directory |
|
if (path_info.depth == 0) { |
|
let s = sub_list.querySelector('form span'); |
|
sub_list.appendChild(s); |
|
sub_list.removeChild(sub_list.querySelector('form')); |
|
} else { |
|
sub_list.querySelector('form').addEventListener('change', function(e){ |
|
updateMediaType(sub_list, e.target.value); |
|
}); |
|
} |
|
|
|
// NOTE: hide nested folders by default and add listener to open/close children |
|
if (path_info.depth > 1) |
|
sub_list.classList.add('hidden'); |
|
|
|
if (path_info.depth > 0) { |
|
sub_list.addEventListener('click', function(e) { |
|
e.stopPropagation(); |
|
|
|
if (e.target.nodeName != 'INPUT') { |
|
for (let div of sub_list.querySelectorAll('div')) |
|
div.classList.toggle('hidden'); |
|
} |
|
}); |
|
} |
|
|
|
for (let node of path_info.contents) |
|
sub_list.appendChild(buildDirectoryTreeWithData(node)); |
|
|
|
return clone; |
|
} |
|
|
|
function createJSONFromDOM(node) |
|
{ |
|
let json = {}; |
|
json.base_name = node.dataset.baseName; |
|
json.content_size = node.dataset.contentSize; |
|
json.depth = node.dataset.depth; |
|
json.path_extension = node.dataset.fileExtension; |
|
json.full_path = node.dataset.fullPath; |
|
json.media_type = node.dataset.mediaType; |
|
json.path_type = node.dataset.pathType; |
|
json.contents = []; |
|
|
|
return json; |
|
} |
|
|
|
function buildJSONFromNode(node) |
|
{ |
|
let json = createJSONFromDOM(node); |
|
|
|
if (json.media_type == "unknown" || json.media_type == "") { |
|
throw new Error('unknown media type, ' + json.base_name + ', at depth: ' + json.depth + '.\n'); |
|
return null; |
|
} |
|
|
|
if (node.childNodes.length > 1) { |
|
for (let child of node.children) { |
|
if (child.nodeName == 'DIV') |
|
json.contents.push(buildJSONFromNode(child)); |
|
} |
|
} |
|
|
|
return json; |
|
} |
|
|
|
function onScanSubmit(e) |
|
{ |
|
console.log('onScanSubmit'); |
|
|
|
let errors = document.querySelector('#errors'); |
|
let error_count = 0; |
|
div = document.querySelector('#main_container div'); |
|
let json = createJSONFromDOM(div); |
|
|
|
for (let node of div.children) { |
|
if (node.nodeName == 'DIV') { |
|
try { |
|
json.contents.push(buildJSONFromNode(node)); |
|
} catch(e) { |
|
console.log(e); |
|
errors.appendChild(document.createTextNode(e.message)); |
|
error_count++; |
|
} |
|
} |
|
} |
|
|
|
if (error_count == 0) { |
|
console.log('valid json, uploading'); |
|
fetchPOSTJSON(VERIFY_URL, json, function() { |
|
// ?? |
|
}); |
|
} else { |
|
console.log('failed upload, errors in json'); |
|
} |
|
|
|
console.log(json); |
|
} |
|
|
|
function scanFolderResponse(data) |
|
{ |
|
let errors = document.querySelector('#errors'); |
|
let info_container = document.querySelector('#info pre'); |
|
let main_container = document.querySelector('#main_container'); |
|
resetContainers(errors, info_container, main_container); |
|
|
|
if (data.errors) { |
|
for (let err of data.errors) { |
|
errors.appendChild(document.createTextNode(err)); |
|
console.log(err); |
|
} |
|
} |
|
|
|
if (data.mem_usage) { |
|
info_container.appendChild(document.createTextNode( |
|
'memory usage: ' + data.mem_usage + ' bytes') |
|
); |
|
} |
|
|
|
if (data.path_info) { |
|
let b = document.createElement('button'); |
|
b.textContent = 'Upload'; |
|
b.addEventListener('click', onScanSubmit); |
|
main_container.appendChild(b); |
|
|
|
main_container.appendChild(buildDirectoryTreeWithData(data.path_info)); |
|
} |
|
} |
|
|
|
window.onload = function () { |
|
if (!('fetch' in window)) { |
|
console.log('no fetch API'); |
|
return; |
|
} |
|
|
|
let scan_button = document.querySelector('#scan_button'); |
|
|
|
scan_button.addEventListener('click', function(e) { |
|
let info_container = document.querySelector('#info pre'); |
|
resetContainers(info_container); |
|
info_container.appendChild(document.createTextNode('waiting for response...')); |
|
fetchJSON(SCAN_URL, scanFolderResponse); |
|
}); |
|
}
|
|
|