mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Updating DirectorySearch to allow creation of new directories.
This commit is contained in:
parent
555cdab25c
commit
4b6fb1d37f
11 changed files with 227 additions and 247 deletions
152
app/src/api.js
152
app/src/api.js
|
|
@ -96,7 +96,7 @@ export async function createChannel(channel) {
|
|||
export async function deleteChannel(channelId) {
|
||||
const response = await apiDelete(`${VIDEOS_API}/channels/${channelId}`);
|
||||
if (response.status !== 204) {
|
||||
const message = getErrorMessage(response, 'Failed to delete channel.');
|
||||
const message = await getErrorMessage(response, 'Failed to delete channel.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Unexpected server response',
|
||||
|
|
@ -112,7 +112,7 @@ export async function getChannels() {
|
|||
if (response.status === 200) {
|
||||
return (await response.json())['channels'];
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Failed to get channels.');
|
||||
const message = await getErrorMessage(response, 'Failed to get channels.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Unexpected server response',
|
||||
|
|
@ -153,7 +153,7 @@ export async function tagChannelInfo(channelId, tagName) {
|
|||
if (response.ok) {
|
||||
return (await response.json()).videos_destination;
|
||||
}
|
||||
const message = getErrorMessage(response, 'Failed to get channel tag info.');
|
||||
const message = await getErrorMessage(response, 'Failed to get channel tag info.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Getting Channel Tag Info Failed',
|
||||
|
|
@ -188,7 +188,7 @@ export async function searchVideos(offset, limit, channelId, searchStr, order_by
|
|||
let data = await response.json();
|
||||
return [data['file_groups'], data['totals']['file_groups']];
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Failed to search videos.');
|
||||
const message = await getErrorMessage(response, 'Failed to search videos.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Searching Videos failed',
|
||||
|
|
@ -218,7 +218,7 @@ export async function deleteVideos(videoIds) {
|
|||
const i = videoIds.join(',');
|
||||
const response = await apiDelete(`${VIDEOS_API}/video/${i}`);
|
||||
if (response.status !== 204) {
|
||||
const message = getErrorMessage(response, 'Failed to delete videos.');
|
||||
const message = await getErrorMessage(response, 'Failed to delete videos.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Deleting Videos failed',
|
||||
|
|
@ -258,7 +258,7 @@ export async function getStatus() {
|
|||
if (response.status === 200) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not get server status.');
|
||||
const message = await getErrorMessage(response, 'Could not get server status.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Fetching Status Failed',
|
||||
|
|
@ -273,7 +273,7 @@ export async function getSettings() {
|
|||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not get settings.');
|
||||
const message = await getErrorMessage(response, 'Could not get settings.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Fetching Settings Failed',
|
||||
|
|
@ -286,7 +286,7 @@ export async function getSettings() {
|
|||
export async function saveSettings(settings) {
|
||||
const response = await apiPatch(`${API_URI}/settings`, settings);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Could not save settings.');
|
||||
const message = await getErrorMessage(response, 'Could not save settings.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Saving Settings Failed',
|
||||
|
|
@ -302,7 +302,7 @@ export async function getDownloads() {
|
|||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not get downloads.');
|
||||
const message = await getErrorMessage(response, 'Could not get downloads.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Getting Downloads Failed',
|
||||
|
|
@ -321,7 +321,7 @@ export async function getConfigs() {
|
|||
configs: data.configs,
|
||||
}
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not get configs.');
|
||||
const message = await getErrorMessage(response, 'Could not get configs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Getting Configs Failed',
|
||||
|
|
@ -336,7 +336,7 @@ export async function postImportConfig(fileName) {
|
|||
const body = {file_name: fileName};
|
||||
const response = await apiPost(`${API_URI}/configs/import`, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Could not import config.');
|
||||
const message = await getErrorMessage(response, 'Could not import config.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Importing config Failed',
|
||||
|
|
@ -351,7 +351,7 @@ export async function postSaveConfig(fileName) {
|
|||
const body = {file_name: fileName, overwrite: true};
|
||||
const response = await apiPost(`${API_URI}/configs/save`, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Could not save config.');
|
||||
const message = await getErrorMessage(response, 'Could not save config.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Saving config Failed',
|
||||
|
|
@ -376,7 +376,7 @@ export async function getVideosStatistics() {
|
|||
if (response.status === 200) {
|
||||
return (await response.json())['statistics'];
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not get statistics.');
|
||||
const message = await getErrorMessage(response, 'Could not get statistics.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Getting Statistics Failed',
|
||||
|
|
@ -409,7 +409,7 @@ export async function createChannelDownload(channelId, url, frequency, title_inc
|
|||
time: 5000,
|
||||
});
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not create Channel download.');
|
||||
const message = await getErrorMessage(response, 'Could not create Channel download.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Creating Channel Download Failed',
|
||||
|
|
@ -443,7 +443,7 @@ export async function updateChannelDownload(channelId, downloadId, url, frequenc
|
|||
time: 5000,
|
||||
});
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not update Channel download.');
|
||||
const message = await getErrorMessage(response, 'Could not update Channel download.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Updating Channel Download Failed',
|
||||
|
|
@ -459,7 +459,7 @@ export async function refreshChannel(channelId) {
|
|||
let url = `${VIDEOS_API}/channels/refresh/${channelId}`;
|
||||
const response = await apiPost(url);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, "Failed to refresh this channel's directory");
|
||||
const message = await getErrorMessage(response, "Failed to refresh this channel's directory");
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Failed to refresh',
|
||||
|
|
@ -476,7 +476,7 @@ export async function encryptOTP(otp, plaintext) {
|
|||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Failed to encrypt OTP. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Failed to encrypt OTP. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Failed to encrypt OTP',
|
||||
|
|
@ -492,7 +492,7 @@ export async function decryptOTP(otp, ciphertext) {
|
|||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Failed to decrypt OTP. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Failed to decrypt OTP. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Failed to decrypt OTP',
|
||||
|
|
@ -507,7 +507,7 @@ export async function getCategories() {
|
|||
if (response.ok) {
|
||||
return (await response.json())['categories'];
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not get categories');
|
||||
const message = await getErrorMessage(response, 'Could not get categories');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -519,7 +519,7 @@ export async function getBrands() {
|
|||
if (response.ok) {
|
||||
return (await response.json())['brands'];
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not get brands');
|
||||
const message = await getErrorMessage(response, 'Could not get brands');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -531,7 +531,7 @@ export async function getInventories() {
|
|||
if (response.ok) {
|
||||
return (await response.json())['inventories'];
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not get inventories');
|
||||
const message = await getErrorMessage(response, 'Could not get inventories');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -543,7 +543,7 @@ export async function getInventory(inventoryId) {
|
|||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not get inventory');
|
||||
const message = await getErrorMessage(response, 'Could not get inventory');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -553,7 +553,7 @@ export async function getInventory(inventoryId) {
|
|||
export async function saveInventory(inventory) {
|
||||
const response = await apiPost(`${API_URI}/inventory`, inventory);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to save inventory');
|
||||
const message = await getErrorMessage(response, 'Failed to save inventory');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -565,7 +565,7 @@ export async function updateInventory(inventoryId, inventory) {
|
|||
delete inventory['id'];
|
||||
const response = await apiPut(`${API_URI}/inventory/${inventoryId}`, inventory);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to update inventory');
|
||||
const message = await getErrorMessage(response, 'Failed to update inventory');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -576,7 +576,7 @@ export async function updateInventory(inventoryId, inventory) {
|
|||
export async function deleteInventory(inventoryId) {
|
||||
const response = await apiDelete(`${API_URI}/inventory/${inventoryId}`);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to delete inventory');
|
||||
const message = await getErrorMessage(response, 'Failed to delete inventory');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -589,7 +589,7 @@ export async function getItems(inventoryId) {
|
|||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Failed to get items');
|
||||
const message = await getErrorMessage(response, 'Failed to get items');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -602,7 +602,7 @@ export async function saveItem(inventoryId, item) {
|
|||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Failed to save item');
|
||||
const message = await getErrorMessage(response, 'Failed to save item');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -616,7 +616,7 @@ export async function updateItem(itemId, item) {
|
|||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Failed to update item');
|
||||
const message = await getErrorMessage(response, 'Failed to update item');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -630,7 +630,7 @@ export async function deleteItems(itemIds) {
|
|||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Failed to delete items');
|
||||
const message = await getErrorMessage(response, 'Failed to delete items');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -651,7 +651,7 @@ export async function deleteArchives(archiveIds) {
|
|||
let i = archiveIds.join(',');
|
||||
const response = await apiDelete(`${API_URI}/archive/${i}`);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to delete archives');
|
||||
const message = await getErrorMessage(response, 'Failed to delete archives');
|
||||
toast({
|
||||
type: 'error', title: 'Unexpected server response', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -687,7 +687,7 @@ export async function searchArchives(offset, limit, domain, searchStr, order, ta
|
|||
let data = await response.json();
|
||||
return [data['file_groups'], data['totals']['file_groups']];
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Cannot search archives. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Cannot search archives. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Unable to search archives',
|
||||
|
|
@ -704,7 +704,7 @@ export async function fetchDomains() {
|
|||
let data = await response.json();
|
||||
return [data['domains'], data['totals']['domains']];
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Unable to fetch Domains. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Unable to fetch Domains. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Domains Error',
|
||||
|
|
@ -720,7 +720,7 @@ export async function getArchive(archiveId) {
|
|||
const data = await response.json();
|
||||
return [data['file_group'], data['history']];
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Unable to get Archive. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Unable to get Archive. See server logs.');
|
||||
toast({
|
||||
type: 'error', title: 'Archive Error', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -773,7 +773,7 @@ export async function postDownload(
|
|||
};
|
||||
const response = await apiPost(`${API_URI}/download`, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Unable to create Download. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Unable to create Download. See server logs.');
|
||||
toast({
|
||||
type: 'error', title: 'Download Error', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -809,7 +809,7 @@ export async function putDownload(
|
|||
};
|
||||
const response = await apiPut(`${API_URI}/download/${download_id}`, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Unable to update Download. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Unable to update Download. See server logs.');
|
||||
toast({
|
||||
type: 'error', title: 'Download Error', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -820,7 +820,7 @@ export async function putDownload(
|
|||
export async function killDownload(download_id) {
|
||||
const response = await apiPost(`${API_URI}/download/${download_id}/kill`);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Unable to stop Download. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Unable to stop Download. See server logs.');
|
||||
toast({
|
||||
type: 'error', title: 'Download Error', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -831,7 +831,7 @@ export async function killDownload(download_id) {
|
|||
export async function restartDownload(download_id) {
|
||||
const response = await apiPost(`${API_URI}/download/${download_id}/restart`);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Unable to restart Download. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Unable to restart Download. See server logs.');
|
||||
toast({
|
||||
type: 'error', title: 'Download Error', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -842,7 +842,7 @@ export async function restartDownload(download_id) {
|
|||
export async function killDownloads() {
|
||||
const response = await apiPost(`${API_URI}/download/kill`);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Unable to stop downloading. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Unable to stop downloading. See server logs.');
|
||||
toast({
|
||||
type: 'error', title: 'Download Error', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -853,7 +853,7 @@ export async function killDownloads() {
|
|||
export async function startDownloads() {
|
||||
const response = await apiPost(`${API_URI}/download/enable`);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Unable to start downloading. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Unable to start downloading. See server logs.');
|
||||
toast({
|
||||
type: 'error', title: 'Download Error', description: message, time: 5000,
|
||||
});
|
||||
|
|
@ -875,7 +875,7 @@ export async function deleteDownload(downloadId) {
|
|||
try {
|
||||
const response = await apiDelete(`${API_URI}/download/${downloadId}`);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Unable to delete the download. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Unable to delete the download. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Download Error',
|
||||
|
|
@ -919,7 +919,7 @@ export async function filesSearch(offset, limit, searchStr, mimetypes, model, ta
|
|||
let [file_groups, total] = [data['file_groups'], data['totals']['file_groups']];
|
||||
return [file_groups, total];
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Cannot search files. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Cannot search files. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Unable to search files',
|
||||
|
|
@ -942,7 +942,7 @@ export async function refreshFiles(paths) {
|
|||
response = await apiPost(`${API_URI}/files/refresh`);
|
||||
}
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Cannot refresh files. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Cannot refresh files. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Files Error',
|
||||
|
|
@ -957,7 +957,7 @@ export async function makeDirectory(path) {
|
|||
const body = {path: path};
|
||||
const response = await apiPost(`${API_URI}/files/directory`, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to create directory. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Failed to create directory. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Unable to create directory',
|
||||
|
|
@ -983,7 +983,7 @@ export async function getFile(path) {
|
|||
const {file} = await response.json();
|
||||
return file;
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Failed to get file data. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Failed to get file data. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Files Error',
|
||||
|
|
@ -997,7 +997,7 @@ export async function deleteFile(paths) {
|
|||
let body = {paths: paths};
|
||||
const response = await apiPost(`${API_URI}/files/delete`, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to delete file. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Failed to delete file. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Files Error',
|
||||
|
|
@ -1036,7 +1036,7 @@ export async function setHotspot(on) {
|
|||
time: 5000,
|
||||
});
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not modify hotspot. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Could not modify hotspot. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Hotspot Error',
|
||||
|
|
@ -1067,7 +1067,7 @@ export async function setThrottle(on) {
|
|||
time: 5000,
|
||||
});
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not modify throttle. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Could not modify throttle. See server logs.');
|
||||
toast({type: 'error', title: 'Throttle Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1078,7 +1078,7 @@ export async function getMapImportStatus() {
|
|||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Could not get import status');
|
||||
const message = await getErrorMessage(response, 'Could not get import status');
|
||||
toast({type: 'error', title: 'Map Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1087,7 +1087,7 @@ export async function importMapFiles(paths) {
|
|||
let body = {'files': paths};
|
||||
const response = await apiPost(`${API_URI}/map/import`, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Could not start import! See server logs.');
|
||||
const message = await getErrorMessage(response, 'Could not start import! See server logs.');
|
||||
toast({type: 'error', title: 'Map Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1095,7 +1095,7 @@ export async function importMapFiles(paths) {
|
|||
export async function clearCompletedDownloads() {
|
||||
const response = await apiPost(`${API_URI}/download/clear_completed`);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Could not clear completed downloads! See server logs.');
|
||||
const message = await getErrorMessage(response, 'Could not clear completed downloads! See server logs.');
|
||||
toast({type: 'error', title: 'Downloads Error', description: message, time: 5000});
|
||||
}
|
||||
return response
|
||||
|
|
@ -1104,7 +1104,7 @@ export async function clearCompletedDownloads() {
|
|||
export async function deleteOnceDownloads() {
|
||||
const response = await apiPost(`${API_URI}/download/delete_once`);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Could not delete once downloads! See server logs.');
|
||||
const message = await getErrorMessage(response, 'Could not delete once downloads! See server logs.');
|
||||
toast({type: 'error', title: 'Downloads Error', description: message, time: 5000});
|
||||
}
|
||||
return response
|
||||
|
|
@ -1113,7 +1113,7 @@ export async function deleteOnceDownloads() {
|
|||
export async function retryOnceDownloads() {
|
||||
const response = await apiPost(`${API_URI}/download/retry_once`);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Could not retry once downloads! See server logs.');
|
||||
const message = await getErrorMessage(response, 'Could not retry once downloads! See server logs.');
|
||||
toast({type: 'error', title: 'Downloads Error', description: message, time: 5000});
|
||||
}
|
||||
return response
|
||||
|
|
@ -1124,7 +1124,7 @@ export async function getStatistics() {
|
|||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Unable to get file statistics');
|
||||
const message = await getErrorMessage(response, 'Unable to get file statistics');
|
||||
toast({type: 'error', title: 'Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1168,7 +1168,7 @@ export async function tagFileGroup(fileGroup, name) {
|
|||
const uri = `${API_URI}/files/tag`;
|
||||
const response = await apiPost(uri, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Unable to add tag');
|
||||
const message = await getErrorMessage(response, 'Unable to add tag');
|
||||
toast({type: 'error', title: 'Tag Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1188,7 +1188,7 @@ export async function untagFileGroup(fileGroup, name) {
|
|||
const uri = `${API_URI}/files/untag`;
|
||||
const response = await apiPost(uri, body)
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Unable to untag');
|
||||
const message = await getErrorMessage(response, 'Unable to untag');
|
||||
toast({type: 'error', title: 'Tag Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1209,7 +1209,7 @@ export async function saveTag(name, color, id) {
|
|||
type: 'info', title: 'Created new tag', description: `Created new tag: ${name}`, time: 2000,
|
||||
});
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Unable to save tag');
|
||||
const message = await getErrorMessage(response, 'Unable to save tag');
|
||||
toast({type: 'error', title: 'Tag Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1219,7 +1219,7 @@ export async function deleteTag(id, name) {
|
|||
const response = await apiDelete(uri);
|
||||
if (response.status === 400) {
|
||||
const content = await response.json();
|
||||
const message = getErrorMessage(response, 'Cannot delete, Tag is used');
|
||||
const message = await getErrorMessage(response, 'Cannot delete, Tag is used');
|
||||
if (content['code'] === 'USED_TAG') {
|
||||
toast({
|
||||
type: 'error', title: 'Error!', description: message, time: 5000,
|
||||
|
|
@ -1227,7 +1227,7 @@ export async function deleteTag(id, name) {
|
|||
}
|
||||
} else if (!response.ok) {
|
||||
console.error('Failed to delete tag');
|
||||
const message = getErrorMessage(response, `Unable to delete tag: ${name}`);
|
||||
const message = await getErrorMessage(response, `Unable to delete tag: ${name}`);
|
||||
toast({type: 'error', title: 'Tag Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1241,7 +1241,7 @@ export async function fetchFile(path) {
|
|||
return content['file'];
|
||||
} else {
|
||||
console.error('Unable to fetch file dict! See client logs.');
|
||||
const message = getErrorMessage(response, 'Unable to get File');
|
||||
const message = await getErrorMessage(response, 'Unable to get File');
|
||||
toast({type: 'error', title: 'File Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1252,20 +1252,26 @@ export async function sendNotification(message, url) {
|
|||
if (response.status === 201) {
|
||||
toast({type: 'success', title: 'Shared', description: 'Your share was sent', time: 2000});
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Your share failed to send!');
|
||||
const message = await getErrorMessage(response, 'Your share failed to send!');
|
||||
toast({type: 'error', title: 'Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
||||
export async function searchDirectories(name) {
|
||||
const body = {name: name || ''};
|
||||
export async function searchDirectories(path) {
|
||||
const body = {path: path || ''};
|
||||
const response = await apiPost(`${API_URI}/files/search_directories`, body);
|
||||
if (response.status === 204) {
|
||||
return [];
|
||||
} else if (response.status === 200) {
|
||||
return await response.json();
|
||||
const content = await response.json();
|
||||
return {
|
||||
is_dir: content.is_dir,
|
||||
directories: content.directories,
|
||||
channel_directories: content.channel_directories,
|
||||
domain_directories: content.domain_directories,
|
||||
}
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Failed to search directories!');
|
||||
const message = await getErrorMessage(response, 'Failed to search directories!');
|
||||
toast({type: 'error', title: 'Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1274,7 +1280,7 @@ export async function renamePath(path, newName) {
|
|||
const body = {path, new_name: newName};
|
||||
const response = await apiPost(`${API_URI}/files/rename`, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to rename!');
|
||||
const message = await getErrorMessage(response, 'Failed to rename!');
|
||||
toast({type: 'error', title: 'Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1283,7 +1289,7 @@ export async function movePaths(destination, paths) {
|
|||
const body = {destination, paths};
|
||||
const response = await apiPost(`${API_URI}/files/move`, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to move!');
|
||||
const message = await getErrorMessage(response, 'Failed to move!');
|
||||
toast({type: 'error', title: 'Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1292,7 +1298,7 @@ export async function ignoreDirectory(directory) {
|
|||
const body = {path: directory};
|
||||
const response = await apiPost(`${API_URI}/files/ignore_directory`, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to ignore directory!');
|
||||
const message = await getErrorMessage(response, 'Failed to ignore directory!');
|
||||
toast({type: 'error', title: 'Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1301,7 +1307,7 @@ export async function unignoreDirectory(directory) {
|
|||
const body = {path: directory};
|
||||
const response = await apiPost(`${API_URI}/files/unignore_directory`, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to unignore directory!');
|
||||
const message = await getErrorMessage(response, 'Failed to unignore directory!');
|
||||
toast({type: 'error', title: 'Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1314,7 +1320,7 @@ export async function fetchZims() {
|
|||
zims: content['zims'],
|
||||
}
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Cannot fetch Zims');
|
||||
const message = await getErrorMessage(response, 'Cannot fetch Zims');
|
||||
toast({type: 'error', title: 'Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1329,7 +1335,7 @@ export async function fetchZimSubscriptions() {
|
|||
iso_639_codes: content['iso_639_codes'],
|
||||
}
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Cannot fetch Zim Subscriptions');
|
||||
const message = await getErrorMessage(response, 'Cannot fetch Zim Subscriptions');
|
||||
toast({type: 'error', title: 'Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1356,7 +1362,7 @@ export async function tagZimEntry(zim_id, zim_entry, name) {
|
|||
const uri = `${API_URI}/zim/tag`;
|
||||
const response = await apiPost(uri, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to add zim tag');
|
||||
const message = await getErrorMessage(response, 'Failed to add zim tag');
|
||||
toast({type: 'error', title: 'Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1367,7 +1373,7 @@ export async function untagZimEntry(zim_id, zim_entry, name) {
|
|||
const uri = `${API_URI}/zim/untag`;
|
||||
const response = await apiPost(uri, body);
|
||||
if (!response.ok) {
|
||||
const message = getErrorMessage(response, 'Failed to untag zim');
|
||||
const message = await getErrorMessage(response, 'Failed to untag zim');
|
||||
toast({type: 'error', title: 'Error', description: message, time: 5000});
|
||||
}
|
||||
}
|
||||
|
|
@ -1472,7 +1478,7 @@ export async function getOutdatedZims() {
|
|||
current: content['current'],
|
||||
}
|
||||
} else {
|
||||
const message = getErrorMessage(response, 'Cannot fetch outdated Zims. See server logs.');
|
||||
const message = await getErrorMessage(response, 'Cannot fetch outdated Zims. See server logs.');
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Error',
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import {
|
|||
import {
|
||||
APIButton,
|
||||
BackButton,
|
||||
DirectoryInput,
|
||||
DirectorySearch,
|
||||
ErrorMessage,
|
||||
frequencyOptions,
|
||||
HelpHeader,
|
||||
|
|
@ -370,10 +370,10 @@ function ChannelPage({create, header}) {
|
|||
<label>
|
||||
Directory <RequiredAsterisk/>
|
||||
</label>
|
||||
<DirectoryInput required
|
||||
value={channel.directory}
|
||||
setInput={value => changeValue('directory', value)}
|
||||
placeholder='videos/channel directory'
|
||||
<DirectorySearch
|
||||
value={channel.directory}
|
||||
setInput={value => changeValue('directory', value)}
|
||||
placeholder='videos/channel directory'
|
||||
/>
|
||||
</FormField>
|
||||
</FormGroup>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import {Link, NavLink, useNavigate, useSearchParams} from "react-router-dom";
|
|||
import Message from "semantic-ui-react/dist/commonjs/collections/Message";
|
||||
import {
|
||||
useCPUTemperature,
|
||||
useDirectories,
|
||||
useHotspot,
|
||||
useLoad,
|
||||
useSearchDirectories,
|
||||
|
|
@ -53,7 +52,6 @@ import {
|
|||
import {FilePreviewContext} from "./FilePreview";
|
||||
import _ from "lodash";
|
||||
import {killDownloads, startDownloads} from "../api";
|
||||
import Grid from "semantic-ui-react/dist/commonjs/collections/Grid";
|
||||
|
||||
export const API_URI = process.env && process.env.REACT_APP_API_URI ? process.env.REACT_APP_API_URI : `https://${window.location.host}/api`;
|
||||
export const VIDEOS_API = `${API_URI}/videos`;
|
||||
|
|
@ -1213,16 +1211,21 @@ export function DirectorySearch({onSelect, value, ...props}) {
|
|||
directories,
|
||||
channelDirectories,
|
||||
domainDirectories,
|
||||
isDir,
|
||||
loading,
|
||||
} = useSearchDirectories(value);
|
||||
const [results, setResults] = useState();
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
(directories && directories.length >= 0)
|
||||
|| (channelDirectories && channelDirectories.length >= 0)
|
||||
|| (domainDirectories && domainDirectories.length >= 0)) {
|
||||
setResults({
|
||||
if (directories && directories.length >= 0) {
|
||||
const newDirectory = isDir ? {} : {
|
||||
newDirectory: {
|
||||
name: 'New Directory',
|
||||
results: [{title: directoryName}],
|
||||
}
|
||||
};
|
||||
const newResults = {
|
||||
...newDirectory,
|
||||
directories: {
|
||||
name: 'Directories',
|
||||
results: directories.map(i => {
|
||||
|
|
@ -1240,8 +1243,9 @@ export function DirectorySearch({onSelect, value, ...props}) {
|
|||
results: domainDirectories.map(i => {
|
||||
return {title: i['path'], description: i['domain']};
|
||||
}),
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
setResults(newResults);
|
||||
}
|
||||
}, [
|
||||
JSON.stringify(directories),
|
||||
|
|
@ -1254,9 +1258,6 @@ export function DirectorySearch({onSelect, value, ...props}) {
|
|||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
if (onSelect) {
|
||||
onSelect('');
|
||||
}
|
||||
setDirectoryName(data.value);
|
||||
}
|
||||
|
||||
|
|
@ -1264,77 +1265,22 @@ export function DirectorySearch({onSelect, value, ...props}) {
|
|||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
setDirectoryName(data.result.title);
|
||||
// title is the relative path.
|
||||
if (onSelect) {
|
||||
onSelect(data.result.title);
|
||||
}
|
||||
setDirectoryName(data.result.title);
|
||||
}
|
||||
|
||||
const handleClear = (e) => {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
onSelect('');
|
||||
setDirectoryName('');
|
||||
}
|
||||
|
||||
return <Grid>
|
||||
<Grid.Row>
|
||||
<Grid.Column mobile={13} tablet={14} computer={15}>
|
||||
<Search category
|
||||
placeholder='Search directory names...'
|
||||
onSearchChange={handleSearchChange}
|
||||
onResultSelect={handleResultSelect}
|
||||
loading={loading}
|
||||
value={directoryName}
|
||||
results={results}
|
||||
{...props}
|
||||
/>
|
||||
</Grid.Column>
|
||||
<Grid.Column mobile={3} tablet={2} computer={1}>
|
||||
<Button secondary icon='close' onClick={handleClear}/>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
}
|
||||
|
||||
export function DirectoryInput({disabled, error, placeholder, setInput, value, required, isDirectory}) {
|
||||
const {directory, directories, setDirectory, isDir} = useDirectories(value);
|
||||
const {settings} = React.useContext(SettingsContext);
|
||||
|
||||
if (!directories || !settings) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const localSetInput = (e, {value}) => {
|
||||
setInput(value);
|
||||
setDirectory(value);
|
||||
}
|
||||
|
||||
let {media_directory} = settings;
|
||||
if (media_directory && !media_directory.endsWith('/')) {
|
||||
media_directory = `${media_directory}/`;
|
||||
}
|
||||
error = error || isDirectory && !isDir;
|
||||
|
||||
return <div>
|
||||
<Input
|
||||
action={{
|
||||
color: error ? 'red' : 'green', labelPosition: 'left', icon: 'folder', content: media_directory,
|
||||
}}
|
||||
required={required}
|
||||
disabled={disabled}
|
||||
actionPosition='left'
|
||||
value={directory}
|
||||
onChange={localSetInput}
|
||||
placeholder={placeholder}
|
||||
list='directories'
|
||||
/>
|
||||
<datalist id='directories'>
|
||||
{directories.map(i => <option key={i} value={i}>{i}</option>)}
|
||||
</datalist>
|
||||
</div>;
|
||||
return <Search category
|
||||
placeholder='Search directory names...'
|
||||
onSearchChange={handleSearchChange}
|
||||
onResultSelect={handleResultSelect}
|
||||
loading={loading}
|
||||
value={directoryName}
|
||||
results={results}
|
||||
{...props}
|
||||
/>
|
||||
}
|
||||
|
||||
export const BackButton = ({...props}) => {
|
||||
|
|
|
|||
|
|
@ -70,7 +70,11 @@ export function Upload({disabled}) {
|
|||
<Form>
|
||||
<SForm.Field required>
|
||||
<label>Destination</label>
|
||||
<DirectorySearch onSelect={handleDestination} disabled={disabled}/>
|
||||
<DirectorySearch
|
||||
onSelect={handleDestination}
|
||||
disabled={disabled}
|
||||
style={{marginBottom: '0.5em'}}
|
||||
/>
|
||||
{tagsSelector}
|
||||
</SForm.Field>
|
||||
</Form>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
encodeMediaPath,
|
||||
getParentDirectory,
|
||||
humanFileSize,
|
||||
humanNumber,
|
||||
humanNumber, isoDatetimeToElapsedPopup,
|
||||
isoDatetimeToString,
|
||||
MultilineText,
|
||||
PageContainer,
|
||||
|
|
@ -367,7 +367,7 @@ function VideoPage({videoFile, prevFile, nextFile, fetchVideo, ...props}) {
|
|||
<Segment>
|
||||
|
||||
<Header as='h2'>{title}</Header>
|
||||
{videoFile.published_datetime && <h3>{isoDatetimeToString(videoFile.published_datetime)}</h3>}
|
||||
{videoFile.published_datetime && <h3>{isoDatetimeToElapsedPopup(videoFile.published_datetime)}</h3>}
|
||||
<h3>
|
||||
{channel && <Link to={`/videos/channel/${channel.id}/video`}>
|
||||
{channel.name}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import {
|
|||
getChannel,
|
||||
getChannels,
|
||||
getConfigs,
|
||||
getDirectories,
|
||||
getDownloads,
|
||||
getFiles,
|
||||
getInventory,
|
||||
|
|
@ -745,58 +744,22 @@ export const useThrottle = () => {
|
|||
return {on, setOn, setThrottle: localSetThrottle};
|
||||
}
|
||||
|
||||
export const useDirectories = (defaultDirectory) => {
|
||||
const [directories, setDirectories] = useState();
|
||||
const [directory, setDirectory] = useState(defaultDirectory);
|
||||
const [exists, setExists] = useState();
|
||||
const [isDir, setIsDir] = useState();
|
||||
const [isFile, setIsFile] = useState();
|
||||
|
||||
const fetchDirectories = async () => {
|
||||
if (defaultDirectory && directory === '') {
|
||||
setDirectory(defaultDirectory);
|
||||
}
|
||||
try {
|
||||
const {directories, is_dir, exists_, is_file} = await getDirectories(directory);
|
||||
setDirectories(directories);
|
||||
setIsDir(is_dir);
|
||||
setExists(exists_);
|
||||
setIsFile(is_file);
|
||||
} catch (e) {
|
||||
toast({
|
||||
type: 'error',
|
||||
title: 'Unexpected server response',
|
||||
description: 'Could not get directories',
|
||||
time: 5000,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchDirectories();
|
||||
}, [directory, defaultDirectory]);
|
||||
|
||||
useEffect(() => {
|
||||
setDirectory(defaultDirectory);
|
||||
}, [defaultDirectory])
|
||||
|
||||
return {directory, directories, setDirectory, exists, isDir, isFile};
|
||||
}
|
||||
|
||||
export const useSearchDirectories = (value) => {
|
||||
const [directoryName, setDirectoryName] = useState(value ?? '');
|
||||
const [directories, setDirectories] = useState(null);
|
||||
const [channelDirectories, setChannelDirectories] = useState(null);
|
||||
const [domainDirectories, setDomainDirectories] = useState(null);
|
||||
const [isDir, setIsDir] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const localSearchDirectories = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const {directories: dirs, channel_directories, domain_directories} = await searchDirectories(directoryName);
|
||||
setDirectories(dirs);
|
||||
setChannelDirectories(channel_directories);
|
||||
setDomainDirectories(domain_directories);
|
||||
const result = await searchDirectories(directoryName);
|
||||
setDirectories(result.directories);
|
||||
setChannelDirectories(result.channel_directories);
|
||||
setDomainDirectories(result.domain_directories);
|
||||
setIsDir(result.is_dir);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
@ -806,13 +769,19 @@ export const useSearchDirectories = (value) => {
|
|||
localSearchDirectories();
|
||||
}, [directoryName]);
|
||||
|
||||
useEffect(() => {
|
||||
// Directory value was changed above.
|
||||
setDirectoryName(value);
|
||||
}, [value]);
|
||||
|
||||
return {
|
||||
directoryName,
|
||||
setDirectoryName,
|
||||
directories,
|
||||
loading,
|
||||
channelDirectories,
|
||||
domainDirectories
|
||||
domainDirectories,
|
||||
isDir,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ After=network.target auditd.service
|
|||
|
||||
[Service]
|
||||
# Delay startup so WROLPi API has time to start.
|
||||
ExecStartPre=/bin/sleep 30
|
||||
ExecStartPre=/bin/sleep 60
|
||||
# Map is intense, but not a high priority.
|
||||
Nice=19
|
||||
ExecStart=/usr/bin/renderd -f
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import pathlib
|
||||
from http import HTTPStatus
|
||||
from typing import List
|
||||
|
||||
import sanic.request
|
||||
from sanic import response, Request, Blueprint
|
||||
|
|
@ -127,31 +126,51 @@ def post_directories(_, body: schema.DirectoriesRequest):
|
|||
|
||||
@files_bp.post('/search_directories')
|
||||
@openapi.definition(
|
||||
summary='Get all directories whose name matches the provided name.',
|
||||
summary='Get all directories whose name matches the provided name or path.',
|
||||
body=schema.DirectoriesSearchRequest,
|
||||
)
|
||||
@validate(schema.DirectoriesSearchRequest)
|
||||
async def post_search_directories(_, body: schema.DirectoriesSearchRequest):
|
||||
if len(body.name) <= 1:
|
||||
return response.empty()
|
||||
if len(body.path) <= 1:
|
||||
# Need more data before searching.
|
||||
return json_response({
|
||||
'is_dir': False,
|
||||
'directories': [],
|
||||
'channel_directories': [],
|
||||
'domain_directories': [],
|
||||
})
|
||||
|
||||
from modules.videos.channel import lib as channels_lib
|
||||
channels = await channels_lib.search_channels_by_name(name=body.name)
|
||||
path = get_media_directory() / body.path
|
||||
|
||||
try:
|
||||
matching_directories = lib.get_matching_directories(str(path))
|
||||
matching_directories = list(map(pathlib.Path, matching_directories))
|
||||
except FileNotFoundError:
|
||||
matching_directories = []
|
||||
|
||||
# Search Channels by name.
|
||||
from modules.videos.channel.lib import search_channels_by_name
|
||||
channels = await search_channels_by_name(name=body.path)
|
||||
channel_directories = [dict(path=i.directory, name=i.name) for i in channels]
|
||||
channel_paths = [i['path'] for i in channel_directories]
|
||||
|
||||
from modules.archive import lib as archives_lib
|
||||
domains = await archives_lib.search_domains_by_name(name=body.name)
|
||||
# Search Domains by name.
|
||||
from modules.archive.lib import search_domains_by_name
|
||||
domains = await search_domains_by_name(name=body.path)
|
||||
domain_directories = [dict(path=i.directory, domain=i.domain) for i in domains]
|
||||
domain_paths = [i['path'] for i in domain_directories]
|
||||
|
||||
# Get all directories that match but do not contain the above directories.
|
||||
from wrolpi.files.models import Directory
|
||||
directories: List[Directory] = await lib.search_directories_by_name(
|
||||
name=body.name,
|
||||
excluded=list(map(str, channel_paths + domain_paths)))
|
||||
# Get all Directory that match but do not contain the above directories.
|
||||
excluded = [str(i) for i in channel_paths + domain_paths + matching_directories]
|
||||
directories = await lib.search_directories_by_name(name=body.path, excluded=excluded)
|
||||
|
||||
# Return only the top 20 directories.
|
||||
directories = [i.__json__() for i in directories]
|
||||
directories.extend([{'path': i, 'name': i.name} for i in matching_directories])
|
||||
directories = list(sorted(directories, key=lambda i: i['path']))[:20]
|
||||
|
||||
body = {
|
||||
'is_dir': path.is_dir(),
|
||||
'directories': directories,
|
||||
'channel_directories': channel_directories,
|
||||
'domain_directories': domain_directories
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class DirectoriesRequest:
|
|||
|
||||
@dataclass
|
||||
class DirectoriesSearchRequest:
|
||||
name: str
|
||||
path: str
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
|
|||
|
|
@ -342,32 +342,54 @@ def test_file_group_tag(test_client):
|
|||
assert 'tag_id' in response.json['error']
|
||||
|
||||
|
||||
def test_search_directories(test_client, test_session, make_files_structure, assert_directories):
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_directories(async_client, test_session, test_directory, make_files_structure,
|
||||
assert_directories):
|
||||
"""Directories can be searched by name."""
|
||||
make_files_structure(['foo/one.txt', 'foo/two.txt', 'bar/one.txt'])
|
||||
request, response = test_client.post('/api/files/refresh')
|
||||
assert response.status_code == HTTPStatus.NO_CONTENT
|
||||
await lib.refresh_files()
|
||||
assert_directories({'foo', 'bar'})
|
||||
# Create directory that was not refreshed.
|
||||
(test_directory / 'baz').mkdir()
|
||||
|
||||
# More than one character required.
|
||||
content = dict(name='f')
|
||||
request, response = test_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.NO_CONTENT
|
||||
content = dict(path='f')
|
||||
request, response = await async_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK, response.content
|
||||
assert response.json['directories'] == []
|
||||
assert response.json['is_dir'] is False
|
||||
|
||||
content = dict(name='fo')
|
||||
request, response = test_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
# Can search using partial directory name.
|
||||
content = dict(path='fo')
|
||||
request, response = await async_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
assert [i['path'] for i in response.json['directories']] == ['foo', ]
|
||||
assert response.json['is_dir'] is False
|
||||
|
||||
# Searching directory exactly.
|
||||
content = dict(path='foo')
|
||||
request, response = await async_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
assert [i['path'] for i in response.json['directories']] == ['foo', ]
|
||||
assert response.json['is_dir'] is True
|
||||
|
||||
# Case is ignored.
|
||||
content = dict(name='BAR')
|
||||
request, response = test_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
content = dict(path='BAR')
|
||||
request, response = await async_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
assert [i['path'] for i in response.json['directories']] == ['bar', ]
|
||||
assert response.json['is_dir'] is False
|
||||
|
||||
# Can search directories not yet in DB.
|
||||
content = dict(path='ba')
|
||||
request, response = await async_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
assert [i['path'] for i in response.json['directories']] == ['bar', 'baz']
|
||||
assert response.json['is_dir'] is False
|
||||
|
||||
# Searching for something that does not exist.
|
||||
content = dict(name='does not exist')
|
||||
request, response = test_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
content = dict(path='does not exist')
|
||||
request, response = await async_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
assert [i['path'] for i in response.json['directories']] == []
|
||||
|
||||
|
|
@ -395,55 +417,69 @@ def test_search_directories(test_client, test_session, make_files_structure, ass
|
|||
'foooooooooooooooooooooo/',
|
||||
'fooooooooooooooooooooooo/',
|
||||
])
|
||||
test_client.post('/api/files/refresh')
|
||||
content = dict(name='fo')
|
||||
request, response = test_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
await async_client.post('/api/files/refresh')
|
||||
content = dict(path='fo')
|
||||
request, response = await async_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
assert [i['path'] for i in response.json['directories']] == [f'f{"o" * i}' for i in range(2, 22)]
|
||||
|
||||
|
||||
def test_post_search_directories(test_session, test_client, make_files_structure):
|
||||
@pytest.mark.asyncio
|
||||
async def test_post_search_directories(test_session, async_client, make_files_structure):
|
||||
"""Directory names can be searched. This endpoint also returns Channel and Domain directories."""
|
||||
channel_dir, domain_dir, _, _ = make_files_structure([
|
||||
channel1_dir, channel2_dir, domain_dir, _ = make_files_structure([
|
||||
'dir1/',
|
||||
'dir2/',
|
||||
'dir3/',
|
||||
'dir4/',
|
||||
])
|
||||
request, response = test_client.post('/api/files/refresh')
|
||||
request, response = await async_client.post('/api/files/refresh')
|
||||
assert response.status_code == HTTPStatus.NO_CONTENT
|
||||
|
||||
from modules.videos.models import Channel
|
||||
channel = Channel(directory=channel_dir, name='Channel Name')
|
||||
channel1 = Channel(directory=channel1_dir, name='Channel Name')
|
||||
channel2 = Channel(directory=channel2_dir, name='OtherChannel')
|
||||
from modules.archive.models import Domain
|
||||
domain = Domain(directory=domain_dir, domain='example.com')
|
||||
test_session.add_all([channel, domain])
|
||||
test_session.add_all([channel1, channel2, domain])
|
||||
test_session.commit()
|
||||
|
||||
content = {'name': 'di'}
|
||||
request, response = test_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
# All directories contain "di". The names of the Channel and Directory do not match.
|
||||
content = {'path': 'di'}
|
||||
request, response = await async_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
assert response.json['directories'] == [{'name': 'dir1', 'path': 'dir1'}, {'name': 'dir2', 'path': 'dir2'},
|
||||
{'name': 'dir3', 'path': 'dir3'}, {'name': 'dir4', 'path': 'dir4'}]
|
||||
assert response.json['channel_directories'] == []
|
||||
assert response.json['domain_directories'] == []
|
||||
|
||||
content = {'name': 'Chan'}
|
||||
request, response = test_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
# Channel name matches.
|
||||
content = {'path': 'Chan'}
|
||||
request, response = await async_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
assert response.json['directories'] == []
|
||||
assert response.json['channel_directories'] == [
|
||||
{'name': 'Channel Name', 'path': 'dir1'},
|
||||
{'name': 'OtherChannel', 'path': 'dir2'},
|
||||
]
|
||||
assert response.json['domain_directories'] == []
|
||||
|
||||
# "OtherChannel" matches even though the case is wrong, and it has a space.
|
||||
content = {'path': 'other channel'}
|
||||
request, response = await async_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
# Channel name matches.
|
||||
assert response.json['directories'] == []
|
||||
assert response.json['channel_directories'] == [{'name': 'Channel Name', 'path': 'dir1'}]
|
||||
assert response.json['channel_directories'] == [{'name': 'OtherChannel', 'path': 'dir2'}]
|
||||
assert response.json['domain_directories'] == []
|
||||
|
||||
content = {'name': 'exam'}
|
||||
request, response = test_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
content = {'path': 'exam'}
|
||||
request, response = await async_client.post('/api/files/search_directories', content=json.dumps(content))
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
# Domain name matches.
|
||||
assert response.json['directories'] == []
|
||||
assert response.json['channel_directories'] == []
|
||||
assert response.json['domain_directories'] == [{'domain': 'example.com', 'path': 'dir2'}]
|
||||
assert response.json['domain_directories'] == [{'domain': 'example.com', 'path': 'dir3'}]
|
||||
|
||||
|
||||
def test_post_upload_directory(test_session, test_client, test_directory, make_files_structure, make_multipart_form):
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class ScrapeHTMLDownloader(Downloader):
|
|||
raise UnrecoverableDownloadError('Destination must be defined')
|
||||
destination = pathlib.Path(destination)
|
||||
if not destination.is_dir():
|
||||
raise UnrecoverableDownloadError(f'Destination does not exist: {destination}')
|
||||
destination.mkdir(parents=True)
|
||||
|
||||
suffix = suffix.lower()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue