mirror of
https://github.com/hkalexling/Mango.git
synced 2026-04-25 00:00:52 -04:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5760ad924e | |||
| fff171c8c9 | |||
| 44ff566a1d | |||
| 853f422964 | |||
| 3bb0917374 | |||
| a86f0d0f34 | |||
| 16a9d7fc2e | |||
| ee2b4abc85 | |||
| a6c2799521 | |||
| 2370e4d2c6 | |||
| 32b0384ea0 | |||
| 50d4ffdb7b | |||
| 96463641f9 | |||
| ddbba5d596 | |||
| 2a04f4531e |
+1
-1
@@ -9,6 +9,6 @@ RUN git clone https://github.com/hkalexling/image_size.cr && cd image_size.cr &&
|
|||||||
|
|
||||||
COPY mango-arm64v8.o .
|
COPY mango-arm64v8.o .
|
||||||
|
|
||||||
RUN cc 'mango-arm64v8.o' -o 'mango' -rdynamic -lxml2 -L/image_size.cr/ext/libwebp -lwebp -L/image_size.cr/ext/stbi -lstbi /myhtml/src/ext/modest-c/lib/libmodest_static.a -L/duktape.cr/src/.build/lib -L/duktape.cr/src/.build/include -lduktape -lm `pkg-config libarchive --libs` -lz `command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libssl || printf %s '-lssl -lcrypto'` `command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libcrypto || printf %s '-lcrypto'` -lgmp -lsqlite3 -lyaml -lpcre -lm /usr/lib/arm-linux-gnueabihf/libgc.so -lpthread /crystal/src/ext/libcrystal.a -levent -lrt -ldl -L/usr/bin/../lib/crystal/lib -L/usr/bin/../lib/crystal/lib
|
RUN cc 'mango-arm64v8.o' -o 'mango' -rdynamic -lxml2 -L/image_size.cr/ext/libwebp -lwebp -L/image_size.cr/ext/stbi -lstbi /myhtml/src/ext/modest-c/lib/libmodest_static.a -L/duktape.cr/src/.build/lib -L/duktape.cr/src/.build/include -lduktape -lm `pkg-config libarchive --libs` -lz `command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libssl || printf %s '-lssl -lcrypto'` `command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libcrypto || printf %s '-lcrypto'` -lgmp -lsqlite3 -lyaml -lpcre -lm /usr/lib/aarch64-linux-gnu/libgc.so -lpthread /crystal/src/ext/libcrystal.a -levent -lrt -ldl -L/usr/bin/../lib/crystal/lib -L/usr/bin/../lib/crystal/lib
|
||||||
|
|
||||||
CMD ["./mango"]
|
CMD ["./mango"]
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ The official docker images are available on [Dockerhub](https://hub.docker.com/r
|
|||||||
### CLI
|
### CLI
|
||||||
|
|
||||||
```
|
```
|
||||||
Mango - Manga Server and Web Reader. Version 0.12.1
|
Mango - Manga Server and Web Reader. Version 0.14.0
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
@@ -142,6 +142,7 @@ Mobile UI:
|
|||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
<a href="https://casinoshunter.com/online-casinos/"><img src="https://i.imgur.com/EJb3wBo.png" width="150" height="auto"></a>
|
<a href="https://casinoshunter.com/online-casinos/"><img src="https://i.imgur.com/EJb3wBo.png" width="150" height="auto"></a>
|
||||||
|
<a href="https://www.browserstack.com/open-source"><img src="https://i.imgur.com/hGJUJXD.png" width="150" height="auto"></a>
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
|
|||||||
+38
-37
@@ -1,28 +1,43 @@
|
|||||||
const gulp = require('gulp');
|
const gulp = require('gulp');
|
||||||
const minify = require("gulp-babel-minify");
|
const babel = require('gulp-babel');
|
||||||
|
const minify = require('gulp-babel-minify');
|
||||||
const minifyCss = require('gulp-minify-css');
|
const minifyCss = require('gulp-minify-css');
|
||||||
const less = require('gulp-less');
|
const less = require('gulp-less');
|
||||||
|
|
||||||
gulp.task('copy-uikit-js', () => {
|
// Copy libraries from node_moduels to public/js
|
||||||
|
gulp.task('copy-js', () => {
|
||||||
return gulp.src([
|
return gulp.src([
|
||||||
|
'node_modules/@fortawesome/fontawesome-free/js/fontawesome.min.js',
|
||||||
|
'node_modules/@fortawesome/fontawesome-free/js/solid.min.js',
|
||||||
'node_modules/uikit/dist/js/uikit.min.js',
|
'node_modules/uikit/dist/js/uikit.min.js',
|
||||||
'node_modules/uikit/dist/js/uikit-icons.min.js'
|
'node_modules/uikit/dist/js/uikit-icons.min.js'
|
||||||
])
|
])
|
||||||
.pipe(gulp.dest('public/js'));
|
.pipe(gulp.dest('public/js'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('copy-fontawesome', () => {
|
// Copy UIKit SVG icons to public/img
|
||||||
return gulp.src([
|
gulp.task('copy-uikit-icons', () => {
|
||||||
'node_modules/@fortawesome/fontawesome-free/js/fontawesome.min.js',
|
return gulp.src('node_modules/uikit/src/images/backgrounds/*.svg')
|
||||||
'node_modules/@fortawesome/fontawesome-free/js/solid.min.js'
|
.pipe(gulp.dest('public/img'));
|
||||||
])
|
|
||||||
.pipe(gulp.dest('public/js'));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('copy-js', gulp.series('copy-uikit-js', 'copy-fontawesome'));
|
// Compile less
|
||||||
|
gulp.task('less', () => {
|
||||||
|
return gulp.src('public/css/*.less')
|
||||||
|
.pipe(less())
|
||||||
|
.pipe(gulp.dest('public/css'));
|
||||||
|
});
|
||||||
|
|
||||||
gulp.task('minify-js', () => {
|
// Transpile and minify JS files and output to dist
|
||||||
return gulp.src('public/js/*.js')
|
gulp.task('babel', () => {
|
||||||
|
return gulp.src(['public/js/*.js', '!public/js/*.min.js'])
|
||||||
|
.pipe(babel({
|
||||||
|
presets: [
|
||||||
|
['@babel/preset-env', {
|
||||||
|
targets: '>0.25%, not dead, ios>=9'
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
}))
|
||||||
.pipe(minify({
|
.pipe(minify({
|
||||||
removeConsole: true,
|
removeConsole: true,
|
||||||
builtIns: false
|
builtIns: false
|
||||||
@@ -30,40 +45,26 @@ gulp.task('minify-js', () => {
|
|||||||
.pipe(gulp.dest('dist/js'));
|
.pipe(gulp.dest('dist/js'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('less', () => {
|
// Minify CSS and output to dist
|
||||||
return gulp.src('public/css/*.less')
|
|
||||||
.pipe(less())
|
|
||||||
.pipe(gulp.dest('public/css'));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('minify-css', () => {
|
gulp.task('minify-css', () => {
|
||||||
return gulp.src('public/css/*.css')
|
return gulp.src('public/css/*.css')
|
||||||
.pipe(minifyCss())
|
.pipe(minifyCss())
|
||||||
.pipe(gulp.dest('dist/css'));
|
.pipe(gulp.dest('dist/css'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('copy-uikit-icons', () => {
|
// Copy static files (includeing images) to dist
|
||||||
return gulp.src('node_modules/uikit/src/images/backgrounds/*.svg')
|
|
||||||
.pipe(gulp.dest('public/img'));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('img', () => {
|
|
||||||
return gulp.src('public/img/*')
|
|
||||||
.pipe(gulp.dest('dist/img'));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('copy-files', () => {
|
gulp.task('copy-files', () => {
|
||||||
return gulp.src('public/*.*')
|
return gulp.src(['public/img/*', 'public/*.*', 'public/js/*.min.js'], {
|
||||||
|
base: 'public'
|
||||||
|
})
|
||||||
.pipe(gulp.dest('dist'));
|
.pipe(gulp.dest('dist'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('default', gulp.parallel(
|
// Set up the public folder for development
|
||||||
gulp.series('copy-js', 'minify-js'),
|
gulp.task('dev', gulp.parallel('copy-js', 'copy-uikit-icons', 'less'));
|
||||||
gulp.series('less', 'minify-css'),
|
|
||||||
gulp.series('copy-uikit-icons', 'img'),
|
|
||||||
'copy-files'
|
|
||||||
));
|
|
||||||
|
|
||||||
gulp.task('dev', gulp.parallel(
|
// Set up the dist folder for deployment
|
||||||
'copy-js', 'less', 'copy-uikit-icons'
|
gulp.task('deploy', gulp.parallel('babel', 'minify-css', 'copy-files'));
|
||||||
));
|
|
||||||
|
// Default task
|
||||||
|
gulp.task('default', gulp.series('dev', 'deploy'));
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
"author": "Alex Ling <hkalexling@gmail.com>",
|
"author": "Alex Ling <hkalexling@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/preset-env": "^7.11.5",
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
|
"gulp-babel": "^8.0.0",
|
||||||
"gulp-babel-minify": "^0.5.1",
|
"gulp-babel-minify": "^0.5.1",
|
||||||
"gulp-less": "^4.0.1",
|
"gulp-less": "^4.0.1",
|
||||||
"gulp-minify-css": "^1.2.4",
|
"gulp-minify-css": "^1.2.4",
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ const search = () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const path = new URL(input).pathname;
|
const path = new URL(input).pathname;
|
||||||
const match = /\/title\/([0-9]+)/.exec(path);
|
const match = /\/(?:title|manga)\/([0-9]+)/.exec(path);
|
||||||
int_id = parseInt(match[1]);
|
int_id = parseInt(match[1]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
int_id = parseInt(input);
|
int_id = parseInt(input);
|
||||||
|
|||||||
+145
-12
@@ -1,12 +1,72 @@
|
|||||||
|
let lastSavedPage = page;
|
||||||
|
let items = [];
|
||||||
|
let longPages = false;
|
||||||
|
|
||||||
$(() => {
|
$(() => {
|
||||||
getPages();
|
getPages();
|
||||||
|
|
||||||
|
const storedMode = localStorage.getItem('mode') || 'continuous';
|
||||||
|
|
||||||
|
setProp('mode', storedMode);
|
||||||
|
updateMode(storedMode, page);
|
||||||
|
$('#mode-select').val(storedMode);
|
||||||
|
|
||||||
$('#page-select').change(() => {
|
$('#page-select').change(() => {
|
||||||
const p = parseInt($('#page-select').val());
|
const p = parseInt($('#page-select').val());
|
||||||
toPage(p);
|
toPage(p);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#mode-select').change(() => {
|
||||||
|
const mode = $('#mode-select').val();
|
||||||
|
const curIdx = parseInt($('#page-select').val());
|
||||||
|
|
||||||
|
updateMode(mode, curIdx);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(window).resize(() => {
|
||||||
|
const mode = getProp('mode');
|
||||||
|
if (mode === 'continuous') return;
|
||||||
|
|
||||||
|
const wideScreen = $(window).width() > $(window).height();
|
||||||
|
const propMode = wideScreen ? 'height' : 'width';
|
||||||
|
setProp('mode', propMode);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the reader mode
|
||||||
|
*
|
||||||
|
* @function updateMode
|
||||||
|
* @param {string} mode - The mode. Can be one of the followings:
|
||||||
|
* {'continuous', 'paged', 'height', 'width'}
|
||||||
|
* @param {number} targetPage - The one-based index of the target page
|
||||||
|
*/
|
||||||
|
const updateMode = (mode, targetPage) => {
|
||||||
|
localStorage.setItem('mode', mode);
|
||||||
|
|
||||||
|
// The mode to be put into the `mode` prop. It can't be `screen`
|
||||||
|
let propMode = mode;
|
||||||
|
|
||||||
|
if (mode === 'paged') {
|
||||||
|
const wideScreen = $(window).width() > $(window).height();
|
||||||
|
propMode = wideScreen ? 'height' : 'width';
|
||||||
|
}
|
||||||
|
|
||||||
|
setProp('mode', propMode);
|
||||||
|
|
||||||
|
if (mode === 'continuous') {
|
||||||
|
waitForPage(items.length, () => {
|
||||||
|
setupScroller();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForPage(targetPage, () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
toPage(targetPage);
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an alpine.js property
|
* Set an alpine.js property
|
||||||
*
|
*
|
||||||
@@ -18,6 +78,17 @@ const setProp = (key, prop) => {
|
|||||||
$('#root').get(0).__x.$data[key] = prop;
|
$('#root').get(0).__x.$data[key] = prop;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an alpine.js property
|
||||||
|
*
|
||||||
|
* @function getProp
|
||||||
|
* @param {string} key - Key of the data property
|
||||||
|
* @return {*} The data property
|
||||||
|
*/
|
||||||
|
const getProp = (key) => {
|
||||||
|
return $('#root').get(0).__x.$data[key];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get dimension of the pages in the entry from the API and update the view
|
* Get dimension of the pages in the entry from the API and update the view
|
||||||
*/
|
*/
|
||||||
@@ -28,7 +99,7 @@ const getPages = () => {
|
|||||||
throw new Error(resp.error);
|
throw new Error(resp.error);
|
||||||
const dimensions = data.dimensions;
|
const dimensions = data.dimensions;
|
||||||
|
|
||||||
const items = dimensions.map((d, i) => {
|
items = dimensions.map((d, i) => {
|
||||||
return {
|
return {
|
||||||
id: i + 1,
|
id: i + 1,
|
||||||
url: `${base_url}api/page/${tid}/${eid}/${i+1}`,
|
url: `${base_url}api/page/${tid}/${eid}/${i+1}`,
|
||||||
@@ -37,13 +108,15 @@ const getPages = () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const avgRatio = items.reduce((acc, cur) => {
|
||||||
|
return acc + cur.height / cur.width
|
||||||
|
}, 0) / items.length;
|
||||||
|
|
||||||
|
console.log(avgRatio);
|
||||||
|
longPages = avgRatio > 2;
|
||||||
|
|
||||||
setProp('items', items);
|
setProp('items', items);
|
||||||
setProp('loading', false);
|
setProp('loading', false);
|
||||||
|
|
||||||
waitForPage(items.length, () => {
|
|
||||||
toPage(page);
|
|
||||||
setupScroller();
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
const errMsg = `Failed to get the page dimensions. ${e}`;
|
const errMsg = `Failed to get the page dimensions. ${e}`;
|
||||||
@@ -60,7 +133,15 @@ const getPages = () => {
|
|||||||
* @param {number} idx - One-based index of the page
|
* @param {number} idx - One-based index of the page
|
||||||
*/
|
*/
|
||||||
const toPage = (idx) => {
|
const toPage = (idx) => {
|
||||||
|
const mode = getProp('mode');
|
||||||
|
if (mode === 'continuous') {
|
||||||
$(`#${idx}`).get(0).scrollIntoView(true);
|
$(`#${idx}`).get(0).scrollIntoView(true);
|
||||||
|
} else {
|
||||||
|
if (idx >= 1 && idx <= items.length) {
|
||||||
|
setProp('curItem', items[idx - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replaceHistory(idx);
|
||||||
UIkit.modal($('#modal-sections')).hide();
|
UIkit.modal($('#modal-sections')).hide();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -126,6 +207,8 @@ const replaceHistory = (idx) => {
|
|||||||
* @function setupScroller
|
* @function setupScroller
|
||||||
*/
|
*/
|
||||||
const setupScroller = () => {
|
const setupScroller = () => {
|
||||||
|
const mode = getProp('mode');
|
||||||
|
if (mode !== 'continuous') return;
|
||||||
$('#root img').each((idx, el) => {
|
$('#root img').each((idx, el) => {
|
||||||
$(el).on('inview', (event, inView) => {
|
$(el).on('inview', (event, inView) => {
|
||||||
if (inView) {
|
if (inView) {
|
||||||
@@ -136,26 +219,76 @@ const setupScroller = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
let lastSavedPage = page;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the backend reading progress if the current page is more than
|
* Update the backend reading progress if:
|
||||||
* five pages away from the last saved page
|
* 1) the current page is more than five pages away from the last
|
||||||
|
* saved page, or
|
||||||
|
* 2) the average height/width ratio of the pages is over 2, or
|
||||||
|
* 3) the current page is the first page, or
|
||||||
|
* 4) the current page is the last page
|
||||||
*
|
*
|
||||||
* @function saveProgress
|
* @function saveProgress
|
||||||
* @param {number} idx - One-based index of the page
|
* @param {number} idx - One-based index of the page
|
||||||
|
* @param {function} cb - Callback
|
||||||
*/
|
*/
|
||||||
const saveProgress = (idx) => {
|
const saveProgress = (idx, cb) => {
|
||||||
if (Math.abs(idx - lastSavedPage) < 5) return;
|
idx = parseInt(idx);
|
||||||
|
if (Math.abs(idx - lastSavedPage) >= 5 ||
|
||||||
|
longPages ||
|
||||||
|
idx === 1 || idx === items.length
|
||||||
|
) {
|
||||||
lastSavedPage = idx;
|
lastSavedPage = idx;
|
||||||
|
console.log('saving progress', idx);
|
||||||
|
|
||||||
const url = `${base_url}api/progress/${tid}/${idx}?${$.param({entry: eid})}`;
|
const url = `${base_url}api/progress/${tid}/${idx}?${$.param({entry: eid})}`;
|
||||||
$.post(url)
|
$.post(url)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.error) throw new Error(data.error);
|
if (data.error) throw new Error(data.error);
|
||||||
|
if (cb) cb();
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
alert('danger', e);
|
alert('danger', e);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark progress to 100% and redirect to the next entry
|
||||||
|
* Used as the onclick handler for the "Next Entry" button
|
||||||
|
*
|
||||||
|
* @function nextEntry
|
||||||
|
* @param {string} nextUrl - URL of the next entry
|
||||||
|
*/
|
||||||
|
const nextEntry = (nextUrl) => {
|
||||||
|
saveProgress(items.length, () => {
|
||||||
|
redirect(nextUrl);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the next or the previous page
|
||||||
|
*
|
||||||
|
* @function flipPage
|
||||||
|
* @param {bool} isNext - Whether we are going to the next page
|
||||||
|
*/
|
||||||
|
const flipPage = (isNext) => {
|
||||||
|
const curItem = getProp('curItem');
|
||||||
|
const idx = parseInt(curItem.id);
|
||||||
|
const delta = isNext ? 1 : -1;
|
||||||
|
const newIdx = idx + delta;
|
||||||
|
|
||||||
|
toPage(newIdx);
|
||||||
|
|
||||||
|
if (isNext)
|
||||||
|
setProp('flipAnimation', 'right');
|
||||||
|
else
|
||||||
|
setProp('flipAnimation', 'left');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
setProp('flipAnimation', null);
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
replaceHistory(newIdx);
|
||||||
|
saveProgress(newIdx);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: mango
|
name: mango
|
||||||
version: 0.12.1
|
version: 0.14.0
|
||||||
|
|
||||||
authors:
|
authors:
|
||||||
- Alex Ling <hkalexling@gmail.com>
|
- Alex Ling <hkalexling@gmail.com>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class Config
|
|||||||
home: true
|
home: true
|
||||||
property plugin_path : String = File.expand_path "~/mango/plugins",
|
property plugin_path : String = File.expand_path "~/mango/plugins",
|
||||||
home: true
|
home: true
|
||||||
|
property download_timeout_seconds : Int32 = 30
|
||||||
property mangadex = Hash(String, String | Int32).new
|
property mangadex = Hash(String, String | Int32).new
|
||||||
|
|
||||||
@[YAML::Field(ignore: true)]
|
@[YAML::Field(ignore: true)]
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ require "option_parser"
|
|||||||
require "clim"
|
require "clim"
|
||||||
require "./plugin/*"
|
require "./plugin/*"
|
||||||
|
|
||||||
MANGO_VERSION = "0.12.1"
|
MANGO_VERSION = "0.14.0"
|
||||||
|
|
||||||
# From http://www.network-science.de/ascii/
|
# From http://www.network-science.de/ascii/
|
||||||
BANNER = %{
|
BANNER = %{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class ReaderRouter < Router
|
|||||||
next layout "reader-error" if entry.err_msg
|
next layout "reader-error" if entry.err_msg
|
||||||
|
|
||||||
# load progress
|
# load progress
|
||||||
page = entry.load_progress username
|
page = [1, entry.load_progress username].max
|
||||||
|
|
||||||
# start from page 1 if the user has finished reading the entry
|
# start from page 1 if the user has finished reading the entry
|
||||||
page = 1 if entry.finished? username
|
page = 1 if entry.finished? username
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ require "http_proxy"
|
|||||||
module HTTP
|
module HTTP
|
||||||
class Client
|
class Client
|
||||||
private def self.exec(uri : URI, tls : TLSContext = nil)
|
private def self.exec(uri : URI, tls : TLSContext = nil)
|
||||||
Logger.debug "Using monkey-patched HTTP::Client"
|
Logger.debug "Setting proxy"
|
||||||
previous_def uri, tls do |client, path|
|
previous_def uri, tls do |client, path|
|
||||||
client.set_proxy get_proxy uri
|
client.set_proxy get_proxy uri
|
||||||
yield client, path
|
yield client, path
|
||||||
|
|||||||
@@ -81,3 +81,15 @@ macro get_sort_opt
|
|||||||
sort_opt = SortOptions.new sort_method, is_ascending
|
sort_opt = SortOptions.new sort_method, is_ascending
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module HTTP
|
||||||
|
class Client
|
||||||
|
private def self.exec(uri : URI, tls : TLSContext = nil)
|
||||||
|
Logger.debug "Setting read timeout"
|
||||||
|
previous_def uri, tls do |client, path|
|
||||||
|
client.read_timeout = Config.current.download_timeout_seconds.seconds
|
||||||
|
yield client, path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@@ -7,9 +7,12 @@
|
|||||||
<link rel="stylesheet" href="<%= base_url %>css/uikit.css" />
|
<link rel="stylesheet" href="<%= base_url %>css/uikit.css" />
|
||||||
<link rel="stylesheet" href="<%= base_url %>css/mango.css" />
|
<link rel="stylesheet" href="<%= base_url %>css/mango.css" />
|
||||||
<link rel="icon" href="<%= base_url %>favicon.ico">
|
<link rel="icon" href="<%= base_url %>favicon.ico">
|
||||||
|
|
||||||
|
<script src="https://polyfill.io/v3/polyfill.min.js?features=matchMedia%2Cdefault&flags=gated"></script>
|
||||||
<script defer src="<%= base_url %>js/fontawesome.min.js"></script>
|
<script defer src="<%= base_url %>js/fontawesome.min.js"></script>
|
||||||
<script defer src="<%= base_url %>js/solid.min.js"></script>
|
<script defer src="<%= base_url %>js/solid.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.5.0/dist/alpine.min.js" defer></script>
|
<script type="module" src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.5.0/dist/alpine.min.js"></script>
|
||||||
|
<script nomodule src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.5.0/dist/alpine-ie11.min.js" defer></script>
|
||||||
<script src="<%= base_url %>js/theme.js"></script>
|
<script src="<%= base_url %>js/theme.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -3,22 +3,32 @@
|
|||||||
|
|
||||||
<%= render_component "head" %>
|
<%= render_component "head" %>
|
||||||
|
|
||||||
<body>
|
<body style="position:relative;">
|
||||||
<div class="uk-section uk-section-default uk-section-small reader-bg">
|
<div class="uk-section uk-section-default uk-section-small reader-bg"
|
||||||
<div class="uk-container uk-container-small">
|
id="root"
|
||||||
<div id="alert"></div>
|
:style="mode === 'continuous' ? '' : 'padding:0'"
|
||||||
<div id="root" x-data="{
|
x-data="{
|
||||||
loading: true,
|
loading: true,
|
||||||
|
mode: 'continuous', // can be 'continuous', 'height' or 'width'
|
||||||
msg: 'Loading the web reader. Please wait...',
|
msg: 'Loading the web reader. Please wait...',
|
||||||
alertClass: 'uk-alert-primary',
|
alertClass: 'uk-alert-primary',
|
||||||
items: []
|
items: [],
|
||||||
|
curItem: {},
|
||||||
|
flipAnimation: null
|
||||||
}">
|
}">
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-small">
|
||||||
|
<div id="alert"></div>
|
||||||
<div x-show="loading">
|
<div x-show="loading">
|
||||||
<div :class="alertClass" x-show="msg" uk-alert>
|
<div :class="alertClass" x-show="msg" uk-alert>
|
||||||
<p x-text="msg"></p>
|
<p x-text="msg"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div x-show="!loading" x-cloak>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
:class="{'uk-container': true, 'uk-container-small': mode === 'continuous', 'uk-container-expand': mode !== 'continuous'}">
|
||||||
|
<div x-show="!loading && mode === 'continuous'" x-cloak>
|
||||||
<template x-for="item in items">
|
<template x-for="item in items">
|
||||||
<img
|
<img
|
||||||
uk-img
|
uk-img
|
||||||
@@ -31,12 +41,28 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<%- if next_entry_url -%>
|
<%- if next_entry_url -%>
|
||||||
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="redirect('<%= next_entry_url %>')">Next Entry</button>
|
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="nextEntry('<%= next_entry_url %>')">Next Entry</button>
|
||||||
<%- else -%>
|
<%- else -%>
|
||||||
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="redirect('<%= exit_url %>')">Exit Reader</button>
|
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="redirect('<%= exit_url %>')">Exit Reader</button>
|
||||||
<%- end -%>
|
<%- end -%>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div x-cloak x-show="!loading && mode !== 'continuous'" class="uk-flex uk-flex-middle" style="height:100vh">
|
||||||
|
|
||||||
|
<img uk-img :class="{
|
||||||
|
'uk-align-center': true,
|
||||||
|
'uk-animation-slide-left': flipAnimation === 'left',
|
||||||
|
'uk-animation-slide-right': flipAnimation === 'right'
|
||||||
|
}" :data-src="curItem.url" :width="curItem.width" :height="curItem.height" :id="curItem.id" @click="showControl($event)" :style="`
|
||||||
|
width:${mode === 'width' ? '100vw' : 'auto'};
|
||||||
|
height:${mode === 'height' ? '100vh' : 'auto'};
|
||||||
|
margin-bottom:0;
|
||||||
|
`" />
|
||||||
|
|
||||||
|
<div style="position:absolute;z-index:1; top:0;left:0; width:30%;height:100%;" @click="flipPage(false)"></div>
|
||||||
|
<div style="position:absolute;z-index:1; top:0;right:0; width:30%;height:100%;" @click="flipPage(true)"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -52,7 +78,7 @@
|
|||||||
<p id="progress-label"></p>
|
<p id="progress-label"></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-margin">
|
<div class="uk-margin">
|
||||||
<label class="uk-form-label" for="form-stacked-select">Jump to page</label>
|
<label class="uk-form-label" for="page-select">Jump to page</label>
|
||||||
<div class="uk-form-controls">
|
<div class="uk-form-controls">
|
||||||
<select id="page-select" class="uk-select">
|
<select id="page-select" class="uk-select">
|
||||||
<%- (1..entry.pages).each do |p| -%>
|
<%- (1..entry.pages).each do |p| -%>
|
||||||
@@ -61,6 +87,15 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="uk-margin">
|
||||||
|
<label class="uk-form-label" for="mode-select">Mode</label>
|
||||||
|
<div class="uk-form-controls">
|
||||||
|
<select id="mode-select" class="uk-select">
|
||||||
|
<option value="continuous">Continuous</option>
|
||||||
|
<option value="paged">Paged</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-modal-footer uk-text-right">
|
<div class="uk-modal-footer uk-text-right">
|
||||||
<button class="uk-button uk-button-danger" type="button" onclick="redirect('<%= exit_url %>')">Exit Reader</button>
|
<button class="uk-button uk-button-danger" type="button" onclick="redirect('<%= exit_url %>')">Exit Reader</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user