Улучшено скачивание файлов - добавлено читабельное имя файла
This commit is contained in:
@@ -124,9 +124,9 @@ class Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async request(params) {
|
async request(params, timeoutSecs = 10) {
|
||||||
while (1) {// eslint-disable-line
|
while (1) {// eslint-disable-line
|
||||||
const response = await wsc.message(await wsc.send(params));
|
const response = await wsc.message(await wsc.send(params), timeoutSecs);
|
||||||
|
|
||||||
if (response && response.error == 'server_busy') {
|
if (response && response.error == 'server_busy') {
|
||||||
await this.showBusyDialog();
|
await this.showBusyDialog();
|
||||||
@@ -166,8 +166,8 @@ class Api {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBookLink(bookPath) {
|
async getBookLink(params) {
|
||||||
const response = await this.request({action: 'get-book-link', bookPath});
|
const response = await this.request(Object.assign({action: 'get-book-link'}, params), 120);
|
||||||
|
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
throw new Error(response.error);
|
throw new Error(response.error);
|
||||||
|
|||||||
@@ -555,26 +555,51 @@ class Search {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async download(book, copy = false) {
|
async download(book, copy = false) {
|
||||||
let downloadFlag = true;
|
if (this.downloadFlag)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.downloadFlag = true;
|
||||||
(async() => {
|
(async() => {
|
||||||
await utils.sleep(200);
|
await utils.sleep(200);
|
||||||
if (downloadFlag)
|
if (this.downloadFlag)
|
||||||
this.loadingMessage2 = 'Подготовка файла...';
|
this.loadingMessage2 = 'Подготовка файла...';
|
||||||
})();
|
})();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const bookPath = `${book.folder}/${book.file}.${book.ext}`;
|
const makeValidFilenameOrEmpty = (s) => {
|
||||||
|
try {
|
||||||
|
return utils.makeValidFilename(s);
|
||||||
|
} catch(e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const response = await this.api.getBookLink(bookPath);
|
//имя файла
|
||||||
|
let downFileName = 'default-name';
|
||||||
|
const author = book.author.split(',');
|
||||||
|
const at = [author[0], book.title];
|
||||||
|
downFileName = makeValidFilenameOrEmpty(at.filter(r => r).join(' - '))
|
||||||
|
|| makeValidFilenameOrEmpty(at[0])
|
||||||
|
|| makeValidFilenameOrEmpty(at[1])
|
||||||
|
|| downFileName;
|
||||||
|
downFileName = `${downFileName.substring(0, 100)}.${book.ext}`;
|
||||||
|
|
||||||
|
const bookPath = `${book.folder}/${book.file}.${book.ext}`;
|
||||||
|
//подготовка
|
||||||
|
const response = await this.api.getBookLink({bookPath, downFileName});
|
||||||
|
|
||||||
const href = `${window.location.origin}${response.link}`;
|
const link = response.link;
|
||||||
|
const href = `${window.location.origin}${link}`;
|
||||||
|
|
||||||
if (!copy) {
|
if (!copy) {
|
||||||
|
//скачивание
|
||||||
const d = this.$refs.download;
|
const d = this.$refs.download;
|
||||||
d.href = href;
|
d.href = href;
|
||||||
|
d.download = downFileName;
|
||||||
|
|
||||||
d.click();
|
d.click();
|
||||||
} else {
|
} else {
|
||||||
|
//копирование ссылки
|
||||||
if (utils.copyTextToClipboard(href))
|
if (utils.copyTextToClipboard(href))
|
||||||
this.$root.notify.success('Ссылка успешно скопирована');
|
this.$root.notify.success('Ссылка успешно скопирована');
|
||||||
else
|
else
|
||||||
@@ -583,7 +608,7 @@ class Search {
|
|||||||
} catch(e) {
|
} catch(e) {
|
||||||
this.$root.stdDialog.alert(e.message, 'Ошибка');
|
this.$root.stdDialog.alert(e.message, 'Ошибка');
|
||||||
} finally {
|
} finally {
|
||||||
downloadFlag = false;
|
this.downloadFlag = false;
|
||||||
this.loadingMessage2 = '';
|
this.loadingMessage2 = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,3 +54,16 @@ export async function copyTextToClipboard(text) {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function makeValidFilename(filename, repl = '_') {
|
||||||
|
let f = filename.replace(/[\x00\\/:*"<>|]/g, repl); // eslint-disable-line no-control-regex
|
||||||
|
f = f.trim();
|
||||||
|
while (f.length && (f[f.length - 1] == '.' || f[f.length - 1] == '_')) {
|
||||||
|
f = f.substring(0, f.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
return f;
|
||||||
|
else
|
||||||
|
throw new Error('Invalid filename');
|
||||||
|
}
|
||||||
|
|||||||
@@ -147,8 +147,10 @@ class WebSocketController {
|
|||||||
async getBookLink(req, ws) {
|
async getBookLink(req, ws) {
|
||||||
if (!utils.hasProp(req, 'bookPath'))
|
if (!utils.hasProp(req, 'bookPath'))
|
||||||
throw new Error(`bookPath is empty`);
|
throw new Error(`bookPath is empty`);
|
||||||
|
if (!utils.hasProp(req, 'downFileName'))
|
||||||
|
throw new Error(`downFileName is empty`);
|
||||||
|
|
||||||
const result = await this.webWorker.getBookLink(req.bookPath);
|
const result = await this.webWorker.getBookLink({bookPath: req.bookPath, downFileName: req.downFileName});
|
||||||
|
|
||||||
this.send(result, req, ws);
|
this.send(result, req, ws);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ class WebWorker {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async restoreBook(bookPath) {
|
async restoreBook(bookPath, downFileName) {
|
||||||
const db = this.db;
|
const db = this.db;
|
||||||
|
|
||||||
const extractedFile = await this.extractBook(bookPath);
|
const extractedFile = await this.extractBook(bookPath);
|
||||||
@@ -333,16 +333,18 @@ class WebWorker {
|
|||||||
replace: true,
|
replace: true,
|
||||||
rows: [
|
rows: [
|
||||||
{id: bookPath, hash},
|
{id: bookPath, hash},
|
||||||
{id: hash, bookPath}
|
{id: hash, bookPath, downFileName}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBookLink(bookPath) {
|
async getBookLink(params) {
|
||||||
this.checkMyState();
|
this.checkMyState();
|
||||||
|
|
||||||
|
const {bookPath, downFileName} = params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const db = this.db;
|
const db = this.db;
|
||||||
let link = '';
|
let link = '';
|
||||||
@@ -360,7 +362,7 @@ class WebWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!link) {
|
if (!link) {
|
||||||
link = await this.restoreBook(bookPath)
|
link = await this.restoreBook(bookPath, downFileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!link)
|
if (!link)
|
||||||
@@ -380,11 +382,13 @@ class WebWorker {
|
|||||||
const db = this.db;
|
const db = this.db;
|
||||||
const hash = path.basename(publicPath);
|
const hash = path.basename(publicPath);
|
||||||
|
|
||||||
//найдем bookPath
|
//найдем bookPath и downFileName
|
||||||
const rows = await db.select({table: 'file_hash', where: `@@id(${db.esc(hash)})`});
|
const rows = await db.select({table: 'file_hash', where: `@@id(${db.esc(hash)})`});
|
||||||
if (rows.length) {//bookPath найден по хешу
|
if (rows.length) {//нашли по хешу
|
||||||
const bookPath = rows[0].bookPath;
|
const rec = rows[0];
|
||||||
await this.restoreBook(bookPath);
|
await this.restoreBook(rec.bookPath, rec.downFileName);
|
||||||
|
|
||||||
|
return rec.downFileName;
|
||||||
} else {//bookPath не найден
|
} else {//bookPath не найден
|
||||||
throw new Error('404 Файл не найден');
|
throw new Error('404 Файл не найден');
|
||||||
}
|
}
|
||||||
@@ -396,6 +400,19 @@ class WebWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getDownFileName(publicPath) {
|
||||||
|
const db = this.db;
|
||||||
|
const hash = path.basename(publicPath);
|
||||||
|
|
||||||
|
//найдем downFileName
|
||||||
|
const rows = await db.select({table: 'file_hash', where: `@@id(${db.esc(hash)})`});
|
||||||
|
if (rows.length) {//downFileName найден по хешу
|
||||||
|
return rows[0].downFileName;
|
||||||
|
} else {//bookPath не найден
|
||||||
|
throw new Error('404 Файл не найден');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async logServerStats() {
|
async logServerStats() {
|
||||||
while (1) {// eslint-disable-line
|
while (1) {// eslint-disable-line
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -163,15 +163,21 @@ function initStatic(app, config) {
|
|||||||
|
|
||||||
const publicPath = `${config.publicDir}${req.path}`;
|
const publicPath = `${config.publicDir}${req.path}`;
|
||||||
|
|
||||||
|
let downFileName = '';
|
||||||
//восстановим
|
//восстановим
|
||||||
try {
|
try {
|
||||||
if (!await fs.pathExists(publicPath)) {
|
if (!await fs.pathExists(publicPath)) {
|
||||||
await webWorker.restoreBookFile(publicPath);
|
downFileName = await webWorker.restoreBookFile(publicPath);
|
||||||
|
} else {
|
||||||
|
downFileName = await webWorker.getDownFileName(publicPath);
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
//quiet
|
//quiet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (downFileName)
|
||||||
|
res.downFileName = downFileName;
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -183,6 +189,9 @@ function initStatic(app, config) {
|
|||||||
setHeaders: (res, filePath) => {
|
setHeaders: (res, filePath) => {
|
||||||
if (path.dirname(filePath) == filesDir) {
|
if (path.dirname(filePath) == filesDir) {
|
||||||
res.set('Content-Encoding', 'gzip');
|
res.set('Content-Encoding', 'gzip');
|
||||||
|
|
||||||
|
if (res.downFileName)
|
||||||
|
res.set('Content-Disposition', `inline; filename*=UTF-8''${encodeURIComponent(res.downFileName)}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user