mirror of
https://github.com/hkalexling/Mango.git
synced 2026-04-25 00:00:52 -04:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5760ad924e | |||
| fff171c8c9 | |||
| 44ff566a1d | |||
| 853f422964 | |||
| 3bb0917374 | |||
| a86f0d0f34 | |||
| 16a9d7fc2e | |||
| ee2b4abc85 |
+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.3
|
Mango - Manga Server and Web Reader. Version 0.14.0
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
+105
-6
@@ -5,12 +5,68 @@ 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
|
||||||
*
|
*
|
||||||
@@ -22,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
|
||||||
*/
|
*/
|
||||||
@@ -50,11 +117,6 @@ const getPages = () => {
|
|||||||
|
|
||||||
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}`;
|
||||||
@@ -71,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) => {
|
||||||
$(`#${idx}`).get(0).scrollIntoView(true);
|
const mode = getProp('mode');
|
||||||
|
if (mode === 'continuous') {
|
||||||
|
$(`#${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();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -137,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) {
|
||||||
@@ -193,3 +265,30 @@ const nextEntry = (nextUrl) => {
|
|||||||
redirect(nextUrl);
|
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.3
|
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.3"
|
MANGO_VERSION = "0.14.0"
|
||||||
|
|
||||||
# From http://www.network-science.de/ascii/
|
# From http://www.network-science.de/ascii/
|
||||||
BANNER = %{
|
BANNER = %{
|
||||||
|
|||||||
+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
|
||||||
|
|||||||
+66
-31
@@ -3,41 +3,67 @@
|
|||||||
|
|
||||||
<%= 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"
|
||||||
|
id="root"
|
||||||
|
:style="mode === 'continuous' ? '' : 'padding:0'"
|
||||||
|
x-data="{
|
||||||
|
loading: true,
|
||||||
|
mode: 'continuous', // can be 'continuous', 'height' or 'width'
|
||||||
|
msg: 'Loading the web reader. Please wait...',
|
||||||
|
alertClass: 'uk-alert-primary',
|
||||||
|
items: [],
|
||||||
|
curItem: {},
|
||||||
|
flipAnimation: null
|
||||||
|
}">
|
||||||
|
|
||||||
<div class="uk-container uk-container-small">
|
<div class="uk-container uk-container-small">
|
||||||
<div id="alert"></div>
|
<div id="alert"></div>
|
||||||
<div id="root" x-data="{
|
<div x-show="loading">
|
||||||
loading: true,
|
<div :class="alertClass" x-show="msg" uk-alert>
|
||||||
msg: 'Loading the web reader. Please wait...',
|
<p x-text="msg"></p>
|
||||||
alertClass: 'uk-alert-primary',
|
|
||||||
items: []
|
|
||||||
}">
|
|
||||||
<div x-show="loading">
|
|
||||||
<div :class="alertClass" x-show="msg" uk-alert>
|
|
||||||
<p x-text="msg"></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div x-show="!loading" x-cloak>
|
|
||||||
<template x-for="item in items">
|
|
||||||
<img
|
|
||||||
uk-img
|
|
||||||
class="uk-align-center"
|
|
||||||
:data-src="item.url"
|
|
||||||
:width="item.width"
|
|
||||||
:height="item.height"
|
|
||||||
:id="item.id"
|
|
||||||
@click="showControl($event)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<%- if next_entry_url -%>
|
|
||||||
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="nextEntry('<%= next_entry_url %>')">Next Entry</button>
|
|
||||||
<%- else -%>
|
|
||||||
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="redirect('<%= exit_url %>')">Exit Reader</button>
|
|
||||||
<%- end -%>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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">
|
||||||
|
<img
|
||||||
|
uk-img
|
||||||
|
class="uk-align-center"
|
||||||
|
:data-src="item.url"
|
||||||
|
:width="item.width"
|
||||||
|
:height="item.height"
|
||||||
|
:id="item.id"
|
||||||
|
@click="showControl($event)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<%- if next_entry_url -%>
|
||||||
|
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="nextEntry('<%= next_entry_url %>')">Next Entry</button>
|
||||||
|
<%- else -%>
|
||||||
|
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="redirect('<%= exit_url %>')">Exit Reader</button>
|
||||||
|
<%- end -%>
|
||||||
|
</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 id="modal-sections" class="uk-flex-top" uk-modal>
|
<div id="modal-sections" class="uk-flex-top" uk-modal>
|
||||||
@@ -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