Repos / pytaku / 75a9c8aa47
commit 75a9c8aa47dd6bbb6496d5e3d205839a4020c134
Author: Bùi Thành Nhân <hi@imnhan.com>
Date:   Sun Aug 9 17:04:06 2020 +0700

    mangasee title/follows view

diff --git a/src/mangoapi/base_site.py b/src/mangoapi/base_site.py
index 79fa6d1..b7f6df2 100644
--- a/src/mangoapi/base_site.py
+++ b/src/mangoapi/base_site.py
@@ -20,6 +20,14 @@ def get_chapter(self, chapter_id):
     def search_title(self, query):
         pass
 
+    @abstractmethod
+    def title_cover(self, title_id, cover_ext):
+        pass
+
+    @abstractmethod
+    def title_source_url(self, title_id):
+        pass
+
     # optional abstract method
     def login(self, username, password):
         raise NotImplementedError()
diff --git a/src/mangoapi/mangadex.py b/src/mangoapi/mangadex.py
index cb5c07b..3ba5cfe 100644
--- a/src/mangoapi/mangadex.py
+++ b/src/mangoapi/mangadex.py
@@ -95,6 +95,12 @@ def login(self, username, password):
         assert md_resp.status_code == 200, md_resp.text
         return dict(md_resp.cookies)
 
+    def title_cover(self, title_id, cover_ext):
+        return f"https://mangadex.org/images/manga/{title_id}.{cover_ext}"
+
+    def title_source_url(self, title_id):
+        return f"https://mangadex.org/manga/{title_id}"
+
 
 # Titles regex slightly adapted from https://github.com/md-y/mangadex-full-api
 # Thanks!
diff --git a/src/mangoapi/mangasee.py b/src/mangoapi/mangasee.py
index 9fd25fe..36e5cae 100644
--- a/src/mangoapi/mangasee.py
+++ b/src/mangoapi/mangasee.py
@@ -1,10 +1,16 @@
 import json
+import re
 
 import apsw
 import requests
 
 from mangoapi.base_site import Site
 
+regexes = {
+    "title_name": re.compile(r"<title>\s*([^|]+) | MangaSee</title>"),
+    "title_chapters": re.compile(r"vm\.Chapters = (\[[^\]]+\])"),
+}
+
 
 class Mangasee(Site):
     search_table = None
@@ -13,7 +19,30 @@ def __init__(self, keyval_store=None):
         self.keyval_store = keyval_store
 
     def get_title(self, title_id):
-        pass
+        resp = requests.get(f"https://mangasee123.com/manga/{title_id}", timeout=3)
+        assert resp.status_code == 200
+        html = resp.text
+        name = regexes["title_name"].search(html).group(1).strip()
+        chapters_str = regexes["title_chapters"].search(html).group(1)
+        chapters = [
+            {
+                "id": ch["Chapter"],
+                "name": ch["ChapterName"],
+                "volume": "",
+                "groups": [],
+                **_parse_chapter_number(ch["Chapter"]),
+            }
+            for ch in json.loads(chapters_str)
+        ]
+        return {
+            "id": title_id,
+            "name": name,
+            "site": "mangasee",
+            "cover_ext": "jpg",
+            "chapters": chapters,
+            "alt_names": [],
+            "descriptions": [],
+        }
 
     def get_chapter(self, chapter_id):
         pass
@@ -60,6 +89,12 @@ def search_title(self, query):
             for row in self.search_table.search(query)
         ]
 
+    def title_cover(self, title_id, cover_ext):
+        return f"https://cover.mangabeast01.com/cover/{title_id}.jpg"
+
+    def title_source_url(self, title_id):
+        return f"https://mangasee123.com/manga/{title_id}"
+
 
 class SearchTable:
     def __init__(self, titles: list):
@@ -84,3 +119,27 @@ def search(self, query):
         return self.db.cursor().execute(
             "SELECT id, name FROM titles(?) ORDER BY rank;", (query,)
         )
+
+
+def _parse_chapter_number(e):
+    """
+    Mangasee author tries to be clever with obtuse chapter numbers that must be decoded
+    via javascript:
+
+        (vm.ChapterDisplay = function (e) {
+        var t = parseInt(e.slice(1, -1)),
+            n = e[e.length - 1];
+        return 0 == n ? t : t + "." + n;
+        })
+
+        Example: vm.ChapterDisplay('100625') === '62.5'
+
+    No idea why tbh.
+    """
+    major = int(e[1:-1])
+    minor = int(e[-1])
+    return {
+        "num_major": major,
+        "num_minor": minor,
+        "number": str(major) if not minor else f"{major}.{minor}",
+    }
diff --git a/src/pytaku/main.py b/src/pytaku/main.py
index 2642a42..ade49d3 100644
--- a/src/pytaku/main.py
+++ b/src/pytaku/main.py
@@ -27,7 +27,13 @@
     unfollow,
     verify_username_password,
 )
-from .source_sites import get_chapter, get_title, search_title_all_sites
+from .source_sites import (
+    get_chapter,
+    get_title,
+    search_title_all_sites,
+    title_cover,
+    title_source_url,
+)
 
 config.load()
 
@@ -50,6 +56,8 @@ def home_view():
 @require_login
 def follows_view():
     titles = get_followed_titles(session["user"]["id"])
+    for title in titles:
+        title["cover"] = title_cover(title["site"], title["id"], title["cover_ext"])
     return render_template("follows.html", titles=titles)
 
 
@@ -169,12 +177,14 @@ def title_view(site, title_id):
     title = load_title(site, title_id, user_id=user_id)
     if not title:
         print("Getting title", title_id)
-        title = get_title(title_id)
+        title = get_title(site, title_id)
         print("Saving title", title_id, "to db")
         save_title(title)
     else:
         print("Loading title", title_id, "from db")
     title["site"] = site
+    title["cover"] = title_cover(site, title_id, title["cover_ext"])
+    title["source_url"] = title_source_url(site, title_id)
     return render_template("title.html", **title)
 
 
diff --git a/src/pytaku/persistence.py b/src/pytaku/persistence.py
index a97ae51..82f2df8 100644
--- a/src/pytaku/persistence.py
+++ b/src/pytaku/persistence.py
@@ -37,7 +37,7 @@ def save_title(title):
         {
             "id": title["id"],
             "name": title["name"],
-            "site": "mangadex",
+            "site": title["site"],
             "cover_ext": title["cover_ext"],
             "chapters": json.dumps(title["chapters"]),
             "alt_names": json.dumps(title["alt_names"]),
diff --git a/src/pytaku/source_sites.py b/src/pytaku/source_sites.py
index d97f43b..44577b6 100644
--- a/src/pytaku/source_sites.py
+++ b/src/pytaku/source_sites.py
@@ -38,12 +38,17 @@ def search_title(site_name, query):
     return _get_site(site_name).search_title(query)
 
 
+def title_cover(site_name, title_id, cover_ext):
+    return _get_site(site_name).title_cover(title_id, cover_ext)
+
+
+def title_source_url(site_name, title_id):
+    return _get_site(site_name).title_source_url(title_id)
+
+
 def search_title_all_sites(query):
     """
     Returns dict in the form of {site_name: List[Title]}
     I should really look into proper type annotations huh.
     """
-    return {
-        site_name: search_title(site_name, query)
-        for site_name in ("mangasee", "mangadex")
-    }
+    return {site_name: search_title(site_name, query) for site_name in ("mangasee",)}
diff --git a/src/pytaku/templates/follows.html b/src/pytaku/templates/follows.html
index ac6dda3..ee57dc9 100644
--- a/src/pytaku/templates/follows.html
+++ b/src/pytaku/templates/follows.html
@@ -23,6 +23,7 @@
 .cover {
   border: 1px solid #777;
   margin-right: .5rem;
+  max-width: 150px;
 }
 .cover:hover {
   box-shadow: 0 0 3px black;
@@ -48,6 +49,7 @@
 .chapter:last-child::after {
   content: '← resume here';
   background-color: cornsilk;
+  white-space: nowrap;
 }
 
 .group {
@@ -73,7 +75,7 @@
   <div>
     <a href="{{ title_url }}">
       <img class="cover"
-           src="https://mangadex.org/images/manga/{{ title['id'] }}.large.jpg"
+           src="{{ title['cover'] }}"
            alt="{{ title['name'] }}" />
     </a>
   </div>
diff --git a/src/pytaku/templates/title.html b/src/pytaku/templates/title.html
index c18cae2..e39ea1d 100644
--- a/src/pytaku/templates/title.html
+++ b/src/pytaku/templates/title.html
@@ -37,10 +37,10 @@ <h1>{{ name }}</h1>
       {{ ibutton(left_icon='bookmark', text=ftext, color=fcolor, title=ftitle) }}
     </form>
   {% endif %}
-  {{ ibutton(href='https://mangadex.org/manga/' + id, right_icon='arrow-up-right', text='Source site', color='blue', title='Go to source site') }}
+  {{ ibutton(href=source_url, right_icon='arrow-up-right', text='Source site', color='blue', title='Go to source site') }}
 </div>
 
-<img class="cover" src="https://mangadex.org/images/manga/{{ id }}.{{ cover_ext }}" alt="cover" />
+<img class="cover" src="{{ cover }}" alt="cover" />
 
 {% if chapters %}
 <table>