From a9a2c9faa866135f1403d9e6884fe2d83cfe603c Mon Sep 17 00:00:00 2001 From: Alex Ling Date: Fri, 26 Feb 2021 10:32:50 +0000 Subject: [PATCH] Finish search for MD --- public/css/mango.less | 4 +- public/js/download.js | 100 +++++++++++++++++++++++++++--------- shard.lock | 2 +- src/routes/api.cr | 44 +++++++++++++++- src/storage.cr | 4 +- src/views/download.html.ecr | 55 ++++++++++++++++++-- 6 files changed, 175 insertions(+), 34 deletions(-) diff --git a/public/css/mango.less b/public/css/mango.less index 3309be4..cd69876 100644 --- a/public/css/mango.less +++ b/public/css/mango.less @@ -34,9 +34,11 @@ .uk-card-body { padding: 20px; .uk-card-title { - max-height: 3em; font-size: 1rem; } + .uk-card-title:not(.free-height) { + max-height: 3em; + } } } diff --git a/public/js/download.js b/public/js/download.js index 4041d6a..d6eed3a 100644 --- a/public/js/download.js +++ b/public/js/download.js @@ -3,9 +3,12 @@ const downloadComponent = () => { chaptersLimit: 1000, loading: false, addingToDownload: false, + searchAvailable: false, searchInput: '', data: {}, chapters: [], + mangaAry: undefined, // undefined: not searching; []: searched but no result + candidateManga: {}, langChoice: 'All', groupChoice: 'All', chapterRange: '', @@ -48,7 +51,21 @@ const downloadComponent = () => { childList: true, subtree: true }); + + $.getJSON(`${base_url}api/admin/mangadex/expires`) + .done((data) => { + if (data.error) { + alert('danger', 'Failed to check MangaDex integration status. Error: ' + data.error); + return; + } + if (data.expires && data.expires > Math.floor(Date.now() / 1000)) + this.searchAvailable = true; + }) + .fail((jqXHR, status) => { + alert('danger', `Failed to check MangaDex integration status. Error: [${jqXHR.status}] ${jqXHR.statusText}`); + }) }, + filtersUpdated() { if (!this.data.chapters) this.chapters = []; @@ -90,10 +107,11 @@ const downloadComponent = () => { console.log('filtered chapters:', _chapters); this.chapters = _chapters; }, + search() { if (this.loading || this.searchInput === '') return; - this.loading = true; this.data = {}; + this.mangaAry = undefined; var int_id = -1; try { @@ -103,29 +121,54 @@ const downloadComponent = () => { } catch (e) { int_id = parseInt(this.searchInput); } - if (int_id <= 0 || isNaN(int_id)) { - alert('danger', 'Please make sure you are using a valid manga ID or manga URL from Mangadex.'); - this.loading = false; - return; + + if (!isNaN(int_id) && int_id > 0) { + // The input is a positive integer. We treat it as an ID. + this.loading = true; + $.getJSON(`${base_url}api/admin/mangadex/manga/${int_id}`) + .done((data) => { + if (data.error) { + alert('danger', 'Failed to get manga info. Error: ' + data.error); + return; + } + + this.data = data; + this.chapters = data.chapters; + this.mangaAry = undefined; + }) + .fail((jqXHR, status) => { + alert('danger', `Failed to get manga info. Error: [${jqXHR.status}] ${jqXHR.statusText}`); + }) + .always(() => { + this.loading = false; + }); + } else { + if (!this.searchAvailable) { + alert('danger', 'Please make sure you are using a valid manga ID or manga URL from Mangadex. If you are trying to search MangaDex with a search term, please log in to MangaDex first by going to "Admin -> Connect to MangaDex"'); + return; + } + + // Search as a search term + this.loading = true; + $.getJSON(`${base_url}api/admin/mangadex/search?${$.param({ + query: this.searchInput + })}`) + .done((data) => { + if (data.error) { + alert('danger', `Failed to search MangaDex. Error: ${data.error}`); + return; + } + + this.mangaAry = data.manga; + this.data = {}; + }) + .fail((jqXHR, status) => { + alert('danger', `Failed to search MangaDex. Error: [${jqXHR.status}] ${jqXHR.statusText}`); + }) + .always(() => { + this.loading = false; + }); } - - $.getJSON(`${base_url}api/admin/mangadex/manga/${int_id}`) - .done((data) => { - if (data.error) { - alert('danger', 'Failed to get manga info. Error: ' + data.error); - return; - } - - this.data = data; - this.chapters = data.chapters; - }) - .fail((jqXHR, status) => { - alert('danger', `Failed to get manga info. Error: [${jqXHR.status}] ${jqXHR.statusText}`); - }) - .always(() => { - this.loading = false; - }); - }, parseRange(str) { @@ -228,6 +271,17 @@ const downloadComponent = () => { this.addingToDownload = false; }); }); + }, + + chooseManga(manga) { + this.candidateManga = manga; + UIkit.modal($('#modal').get(0)).show(); + }, + + confirmManga(id) { + UIkit.modal($('#modal').get(0)).hide(); + this.searchInput = id; + this.search(); } }; }; diff --git a/shard.lock b/shard.lock index b6974f7..254f3a5 100644 --- a/shard.lock +++ b/shard.lock @@ -54,7 +54,7 @@ shards: mangadex: git: https://github.com/hkalexling/mangadex.git - version: 0.6.0+git.commit.d87a1d7a6e84d122814b38618954dcc73fc5553b + version: 0.8.0+git.commit.24e6fb51afd043721139355854e305b43bf98c43 mg: git: https://github.com/hkalexling/mg.git diff --git a/src/routes/api.cr b/src/routes/api.cr index 7599d1e..1e15918 100644 --- a/src/routes/api.cr +++ b/src/routes/api.cr @@ -57,14 +57,16 @@ struct APIRouter } Koa.schema("mdChapter", { + "id" => Int64, "group" => {} of String => String, - }.merge(s %w(id title volume chapter language full_title time + }.merge(s %w(title volume chapter language full_title time manga_title manga_id)), desc: "A MangaDex chapter") Koa.schema "mdManga", { + "id" => Int64, "chapters" => ["mdChapter"], - }.merge(s %w(id title description author artist cover_url)), + }.merge(s %w(title description author artist cover_url)), desc: "A MangaDex manga" Koa.describe "Returns a page in a manga entry" @@ -944,6 +946,44 @@ struct APIRouter end end + Koa.describe "Searches MangaDex for manga matching `query`", <<-MD + Returns an empty list if the current user hasn't logged in to MangaDex. + MD + Koa.query "query" + Koa.response 200, schema: { + "success" => Bool, + "error" => String?, + "manga?" => [{ + "id" => Int64, + "title" => String, + "description" => String, + "mainCover" => String, + }], + } + Koa.tags ["admin", "mangadex"] + get "/api/admin/mangadex/search" do |env| + begin + token, expires = Storage.default.get_md_token get_username env + client = MangaDex::Client.from_config + client.token = token + client.token_expires = expires + + query = env.params.query["query"] + + send_json env, { + "success" => true, + "error" => nil, + "manga" => client.partial_search query, + }.to_json + rescue e + Logger.error e + send_json env, { + "success" => false, + "error" => e.message, + }.to_json + end + end + doc = Koa.generate @@api_json = doc.to_json if doc diff --git a/src/storage.cr b/src/storage.cr index 88a5142..1d47d3f 100644 --- a/src/storage.cr +++ b/src/storage.cr @@ -530,9 +530,9 @@ class Storage end end - def get_md_token(username) : Tuple(String?, Time?) + def get_md_token(username) : Tuple(String?, Time) token = nil - expires = nil + expires = Time.utc MainFiber.run do get_db do |db| db.query_one? "select token, expire from md_account where " \ diff --git a/src/views/download.html.ecr b/src/views/download.html.ecr index a0489c0..0ea8527 100644 --- a/src/views/download.html.ecr +++ b/src/views/download.html.ecr @@ -1,17 +1,39 @@

Download from MangaDex

-
-
- +
+
+
-
+
+ +
-
+
@@ -107,6 +129,29 @@
+ +
<% content_for "script" do %>