├── spec ├── asset │ ├── plugins │ │ └── plugin │ │ │ ├── index.js │ │ │ └── info.json │ └── test-config.yml ├── config_spec.cr ├── spec_helper.cr ├── rename_spec.cr ├── plugin_spec.cr ├── util_spec.cr └── storage_spec.cr ├── public ├── robots.txt ├── favicon.ico ├── img │ ├── banner.png │ ├── loading.gif │ ├── icons │ │ ├── icon.png │ │ ├── icon_x192.png │ │ ├── icon_x512.png │ │ └── icon_x96.png │ └── banner-paddings.png ├── js │ ├── user-edit.js │ ├── alert.js │ ├── user.js │ ├── sort-items.js │ ├── dots.js │ ├── search.js │ ├── jquery.inview.min.js │ ├── admin.js │ ├── missing-items.js │ ├── subscription.js │ ├── download-manager.js │ ├── subscription-manager.js │ ├── common.js │ └── dotdotdot.js ├── manifest.json └── css │ ├── tags.less │ ├── uikit.less │ └── mango.less ├── src ├── views │ ├── message.html.ecr │ ├── components │ │ ├── moment.html.ecr │ │ ├── jquery-ui.html.ecr │ │ ├── uikit.html.ecr │ │ ├── dots.html.ecr │ │ ├── sort-form.html.ecr │ │ ├── head.html.ecr │ │ ├── entry-modal.html.ecr │ │ └── card.html.ecr │ ├── tags.html.ecr │ ├── api.html.ecr │ ├── opds │ │ ├── index.xml.ecr │ │ └── title.xml.ecr │ ├── user.html.ecr │ ├── library.html.ecr │ ├── tag.html.ecr │ ├── reader-error.html.ecr │ ├── missing-items.html.ecr │ ├── login.html.ecr │ ├── user-edit.html.ecr │ ├── admin.html.ecr │ ├── download-manager.html.ecr │ ├── home.html.ecr │ ├── layout.html.ecr │ ├── subscription-manager.html.ecr │ └── title.html.ecr ├── handlers │ ├── cors_handler.cr │ ├── upload_handler.cr │ ├── log_handler.cr │ ├── static_handler.cr │ └── auth_handler.cr ├── routes │ ├── opds.cr │ ├── reader.cr │ ├── admin.cr │ └── main.cr ├── util │ ├── validation.cr │ ├── numeric_sort.cr │ ├── proxy.cr │ ├── chapter_sort.cr │ ├── signature.cr │ ├── web.cr │ └── util.cr ├── main_fiber.cr ├── archive.cr ├── upload.cr ├── server.cr ├── logger.cr ├── plugin │ ├── updater.cr │ ├── subscriptions.cr │ └── downloader.cr ├── library │ ├── archive_entry.cr │ ├── types.cr │ ├── dir_entry.cr │ ├── cache.cr │ └── entry.cr ├── config.cr ├── rename.cr └── mango.cr ├── .dockerignore ├── .gitignore ├── env.example ├── .ameba.yml ├── docker-compose.yml ├── Dockerfile ├── migration ├── tags.4.cr ├── ids.2.cr ├── md_account.11.cr ├── thumbnails.3.cr ├── users.1.cr ├── relative_path_fix.10.cr ├── relative_path.8.cr ├── ids_signature.7.cr ├── titles.5.cr ├── foreign_keys.6.cr ├── unavailable.9.cr └── sort_title.12.cr ├── package.json ├── shard.yml ├── Makefile ├── LICENSE ├── README.md ├── .github └── workflows │ └── docker-mango.yml ├── gulpfile.js ├── shard.lock └── .all-contributorsrc /spec/asset/plugins/plugin/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /spec/asset/test-config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | port: 3000 3 | -------------------------------------------------------------------------------- /src/views/message.html.ecr: -------------------------------------------------------------------------------- 1 |
<%= message %>
2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uparrows/Mango_cn/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/img/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uparrows/Mango_cn/HEAD/public/img/banner.png -------------------------------------------------------------------------------- /public/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uparrows/Mango_cn/HEAD/public/img/loading.gif -------------------------------------------------------------------------------- /src/views/components/moment.html.ecr: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/img/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uparrows/Mango_cn/HEAD/public/img/icons/icon.png -------------------------------------------------------------------------------- /src/views/components/jquery-ui.html.ecr: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/img/banner-paddings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uparrows/Mango_cn/HEAD/public/img/banner-paddings.png -------------------------------------------------------------------------------- /public/img/icons/icon_x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uparrows/Mango_cn/HEAD/public/img/icons/icon_x192.png -------------------------------------------------------------------------------- /public/img/icons/icon_x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uparrows/Mango_cn/HEAD/public/img/icons/icon_x512.png -------------------------------------------------------------------------------- /public/img/icons/icon_x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uparrows/Mango_cn/HEAD/public/img/icons/icon_x96.png -------------------------------------------------------------------------------- /spec/asset/plugins/plugin/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "test", 3 | "title": "Test Plugin", 4 | "placeholder": "placeholder", 5 | "wait_seconds": 1 6 | } 7 | -------------------------------------------------------------------------------- /src/views/components/uikit.html.ecr: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | Dockerfile 4 | Dockerfile.arm32v7 5 | Dockerfile.arm64v8 6 | README.md 7 | .all-contributorsrc 8 | env.example 9 | .github/ 10 | -------------------------------------------------------------------------------- /public/js/user-edit.js: -------------------------------------------------------------------------------- 1 | $(() => { 2 | var target = base_url + 'admin/user/edit'; 3 | if (username) target += username; 4 | $('form').attr('action', target); 5 | if (error) alert('danger', error); 6 | }); 7 | -------------------------------------------------------------------------------- /src/views/components/dots.html.ecr: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/handlers/cors_handler.cr: -------------------------------------------------------------------------------- 1 | class CORSHandler < Kemal::Handler 2 | def call(env) 3 | if request_path_startswith env, ["/api"] 4 | env.response.headers["Access-Control-Allow-Origin"] = "*" 5 | end 6 | call_next env 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /docs/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | *.dwarf 6 | node_modules 7 | yarn.lock 8 | dist 9 | mango 10 | .env 11 | *.md 12 | public/css/uikit.css 13 | public/img/*.svg 14 | public/js/*.min.js 15 | public/css/*.css 16 | public/webfonts 17 | -------------------------------------------------------------------------------- /public/js/alert.js: -------------------------------------------------------------------------------- 1 | const alert = (level, text) => { 2 | $('#alert').empty(); 3 | const html = ``; 4 | $('#alert').append(html); 5 | $("html, body").animate({ scrollTop: 0 }); 6 | }; 7 | -------------------------------------------------------------------------------- /env.example: -------------------------------------------------------------------------------- 1 | # Port that exposes the HTTP frontend 2 | PORT=9000 3 | 4 | # Path to the mango main directory 5 | # This directory holds the database and the library files 6 | MAIN_DIRECTORY_PATH= 7 | 8 | # Path to the mango config directory 9 | # This directory holds the mango configuration path 10 | CONFIG_DIRECTORY_PATH= 11 | -------------------------------------------------------------------------------- /.ameba.yml: -------------------------------------------------------------------------------- 1 | Lint/UselessAssign: 2 | Excluded: 3 | - src/routes/* 4 | - src/server.cr 5 | Lint/UnusedArgument: 6 | Excluded: 7 | - src/routes/* 8 | Metrics/CyclomaticComplexity: 9 | Enabled: false 10 | Layout/LineLength: 11 | Enabled: true 12 | MaxLength: 80 13 | Excluded: 14 | - src/routes/api.cr 15 | - spec/plugin_spec.cr 16 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | mango: 5 | container_name: mango 6 | build: 7 | context: . 8 | dockerfile: ./Dockerfile 9 | expose: 10 | - ${PORT} 11 | ports: 12 | - "${PORT}:9000" 13 | volumes: 14 | - ${MAIN_DIRECTORY_PATH}:/root/mango 15 | - ${CONFIG_DIRECTORY_PATH}:/root/.config/mango 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM crystallang/crystal:1.0.0-alpine AS builder 2 | 3 | WORKDIR /Mango 4 | 5 | COPY . . 6 | RUN apk add --no-cache yarn yaml-static sqlite-static libarchive-dev libarchive-static acl-static expat-static zstd-static lz4-static bzip2-static libjpeg-turbo-dev libpng-dev tiff-dev 7 | RUN make static || make static 8 | 9 | FROM library/alpine 10 | 11 | WORKDIR / 12 | 13 | COPY --from=builder /Mango/mango . 14 | 15 | CMD ["./mango"] 16 | -------------------------------------------------------------------------------- /public/js/user.js: -------------------------------------------------------------------------------- 1 | const remove = (username) => { 2 | $.ajax({ 3 | url: `${base_url}api/admin/user/delete/${username}`, 4 | type: 'DELETE', 5 | dataType: 'json' 6 | }) 7 | .done(data => { 8 | if (data.success) 9 | location.reload(); 10 | else 11 | alert('danger', data.error); 12 | }) 13 | .fail((jqXHR, status) => { 14 | alert('danger', `删除用户失败. Error: [${jqXHR.status}] ${jqXHR.statusText}`); 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /migration/tags.4.cr: -------------------------------------------------------------------------------- 1 | class CreateTags < MG::Base 2 | def up : String 3 | <<-SQL 4 | CREATE TABLE IF NOT EXISTS tags ( 5 | id TEXT NOT NULL, 6 | tag TEXT NOT NULL, 7 | UNIQUE (id, tag) 8 | ); 9 | CREATE INDEX IF NOT EXISTS tags_id_idx ON tags (id); 10 | CREATE INDEX IF NOT EXISTS tags_tag_idx ON tags (tag); 11 | SQL 12 | end 13 | 14 | def down : String 15 | <<-SQL 16 | DROP TABLE tags; 17 | SQL 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /public/js/sort-items.js: -------------------------------------------------------------------------------- 1 | $(() => { 2 | $('#sort-select').change(() => { 3 | const sort = $('#sort-select').find(':selected').attr('id'); 4 | const ary = sort.split('-'); 5 | const by = ary[0]; 6 | const dir = ary[1]; 7 | 8 | const url = `${location.protocol}//${location.host}${location.pathname}`; 9 | const newURL = `${url}?${$.param({ 10 | sort: by, 11 | ascend: dir === 'up' ? 1 : 0 12 | })}`; 13 | window.location.href = newURL; 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/views/tags.html.ecr: -------------------------------------------------------------------------------- 1 |没有找到丢失的条目.
3 | 35 |我们还找不到任何文件。添加一些到您的库中,它们将出现在此处。
7 |<%= Config.current.library_path %>config.yml 其路径为: <%= Config.current.path %>| 关键词 | 79 |种类 | 80 |值 | 81 |
|---|---|---|
90 | 91 |
92 |