Skip to content

Commit

Permalink
feat: add manga and chapter url
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexandreSenpai committed Apr 8, 2024
1 parent db041f8 commit 57624af
Show file tree
Hide file tree
Showing 21 changed files with 244 additions and 115 deletions.
22 changes: 7 additions & 15 deletions .github/workflows/dev-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,16 @@ jobs:
- name: Preparing the environment
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; else python -m pip install beautifulsoup4 requests pydantic expiringdict pytest pytest-cov; fi
if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; else python -m pip install beautifulsoup4 requests pydantic expiringdict pytest; fi
- name: Starting Testing Suites
run: |
ENMA_CACHING_MANGADEX_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGADEX_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGADEX_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGADEX_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_AUTHOR_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
pytest --cov=. --cov-report=xml ./tests
ENMA_CACHING_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
ENMA_CACHING_AUTHOR_TTL_IN_SECONDS='0' \
pytest ./tests
- name: Upload Report to Codecov
uses: codecov/codecov-action@v1
Expand Down
22 changes: 7 additions & 15 deletions .github/workflows/pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,16 @@ jobs:
- name: Preparing the Environment
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; else python -m pip install beautifulsoup4 requests pydantic expiringdict pytest pytest-cov; fi
if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; else python -m pip install beautifulsoup4 requests pydantic expiringdict pytest; fi
- name: Starting Testing Suites
run: |
ENMA_CACHING_MANGADEX_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGADEX_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGADEX_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGADEX_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_AUTHOR_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
pytest --cov=. --cov-report=xml ./tests
ENMA_CACHING_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
ENMA_CACHING_AUTHOR_TTL_IN_SECONDS='0' \
pytest ./tests
- name: Upload Report to Codecov
uses: codecov/codecov-action@v1
Expand Down
18 changes: 5 additions & 13 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,11 @@ jobs:
- name: Starting Testing Suites
run: |
ENMA_CACHING_MANGADEX_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGADEX_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGADEX_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGADEX_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
ENMA_CACHING_NHENTAI_AUTHOR_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_MANGANATO_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
ENMA_CACHING_PAGINATE_TTL_IN_SECONDS='0' \
ENMA_CACHING_SEARCH_TTL_IN_SECONDS='0' \
ENMA_CACHING_GET_TTL_IN_SECONDS='0' \
ENMA_CACHING_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS='0' \
ENMA_CACHING_AUTHOR_TTL_IN_SECONDS='0' \
pytest --cov=. --cov-report=xml ./tests
- name: Upload Report to Codecov
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var/
*.egg-info/
.installed.cfg
*.egg
*.sh

# Installer logs
pip-log.txt
Expand Down
1 change: 0 additions & 1 deletion enma/domain/entities/author_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class ISearchResultProps(TypedDict):
total_results: int
results: list[Manga]

@dataclass
class AuthorPage(Pagination):
"""
Entity class representing a search result in the Enma application.
Expand Down
7 changes: 4 additions & 3 deletions enma/domain/entities/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ def __init__(self,
updated_at: A Union of datetime and None representing when the entity was last updated. Defaults to current UTC time.
"""

self.id = id if id is not None else uuid4()
self.id = id if id is not None else str(uuid4())
self.created_at = created_at if created_at is not None else datetime.utcnow()
self.updated_at = updated_at if updated_at is not None else datetime.utcnow()

def __repr__(self) -> str:
attrs = ', '.join([f"{chave}={valor!r}" for chave, valor in self.__dict__.items()])
return f"{self.__class__.__name__}({attrs})"
non_special_attrs = [f"{chave}={valor!r}" for chave, valor in self.__dict__.items() if not isinstance(valor, list) and not isinstance(valor, dict)]
special_attrs = [f"{chave}={valor!r}" for chave, valor in self.__dict__.items() if isinstance(valor, list) or isinstance(valor, dict)]
return f"{self.__class__.__name__}({', '.join([*non_special_attrs, *special_attrs])})"

def to_dict(self) -> T:
"""Converts the entity to a dictionary.
Expand Down
4 changes: 3 additions & 1 deletion enma/domain/entities/manga.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ class MIME(Enum):
GIF = 'gif'
G = 'gif'


@dataclass
class Image:
uri: str
Expand All @@ -33,6 +32,7 @@ class IMangaProps(TypedDict):
created_at: datetime
updated_at: datetime
title: Title
url: str
pages_count: int
pages: list[Image]

Expand Down Expand Up @@ -115,6 +115,7 @@ class ILanguage(TypedDict):
class Manga(Entity[IMangaProps]):
def __init__(self,
title: Title,
url: str,
chapters: Union[list[Chapter], None] = None,
language: Union[str, None] = None,
genres: Union[list[Genre], None] = None,
Expand All @@ -132,6 +133,7 @@ def __init__(self,
self.title = title
self.language = language
self.cover = cover
self.url = url
self.thumbnail = thumbnail
self.authors = authors or []
self.genres = genres or []
Expand Down
7 changes: 3 additions & 4 deletions enma/domain/entities/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
@dataclass
class Thumb:
id: str
url: str
title: str
cover: Image

Expand All @@ -23,7 +24,6 @@ class ISearchResultProps(TypedDict):
total_results: int
results: list[Manga]

@dataclass
class Pagination(Entity[ISearchResultProps]):
"""
Entity class representing a search result in the Enma application.
Expand All @@ -48,6 +48,5 @@ def __init__(self,

self.page = page
self.results = results or list()
self.total_pages = total_pages or 1 if len(self.results) <= 20 else total_pages
self.total_results = total_results or 20 * self.total_pages if self.total_pages > 1 else len(self.results)

self.total_pages = total_pages
self.total_results = total_results
1 change: 0 additions & 1 deletion enma/domain/entities/search_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class ISearchResultProps(TypedDict):
total_results: int
results: list[Manga]

@dataclass
class SearchResult(Pagination):
"""
Entity class representing a search result in the Enma application.
Expand Down
11 changes: 7 additions & 4 deletions enma/infra/adapters/repositories/mangadex.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Mangadex(IMangaRepository):
"""

def __init__(self) -> None:
self.__SITE_URL = 'https://mangadex.org/'
self.__API_URL = 'https://api.mangadex.org/'
self.__COVER_URL = 'https://mangadex.org/covers/'
self.__HASH_URL = 'https://api.mangadex.org/at-home/server/'
Expand Down Expand Up @@ -126,7 +127,7 @@ def __create_cover_uri(self,
"""
return urljoin(self.__COVER_URL, f'{manga_id}/{file_name}.512.jpg')

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_MANGADEX_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS', 100)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS', 100)),
max_size=20).cache
def fetch_chapter_by_symbolic_link(self,
link: SymbolicLink) -> Chapter:
Expand Down Expand Up @@ -350,6 +351,7 @@ def __parse_full_manga(self,
id=manga_data.get('id'),
created_at=datetime.fromisoformat(attrs.get('createdAt')),
updated_at=datetime.fromisoformat(attrs.get('updatedAt')),
url=urljoin(self.__SITE_URL, f'title/{manga_data.get("id")}'),
language=Language.get(attrs.get('originalLanguage').strip().lower().replace('-', '_'), 'unknown'),
authors=self.__extract_authors(manga_data.get('relationships', list())),
genres=self.__extract_genres(attrs.get('tags', list())),
Expand Down Expand Up @@ -379,10 +381,11 @@ def __parse_thumb(self, manga: IManga) -> Thumb:
title = manga.get('attributes').get('title').get('en')
return Thumb(id=manga.get('id'),
title=title,
url=urljoin(self.__SITE_URL, f'title/{manga.get("id")}'),
cover=self.__get_cover(manga_id=manga.get('id'),
relations=manga.get('relationships', list())))

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_MANGADEX_GET_TTL_IN_SECONDS', 300)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_GET_TTL_IN_SECONDS', 300)),
max_size=20).cache
def get(self,
identifier: str,
Expand Down Expand Up @@ -420,7 +423,7 @@ def __make_sort_query(self, sort: Sort) -> dict[str, str]:
"""
return { f'order[{sort.value if isinstance(sort, Sort) else sort}]': 'desc' }

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_MANGADEX_SEARCH_TTL_IN_SECONDS', 100)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_SEARCH_TTL_IN_SECONDS', 100)),
max_size=5).cache
def search(self,
query: str,
Expand Down Expand Up @@ -466,7 +469,7 @@ def search(self,

return search_result

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_MANGADEX_PAGINATE_TTL_IN_SECONDS', 100)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_PAGINATE_TTL_IN_SECONDS', 100)),
max_size=5).cache
def paginate(self, page: int) -> Pagination:
"""
Expand Down
17 changes: 10 additions & 7 deletions enma/infra/adapters/repositories/manganato.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,11 @@ def __create_chapter(self, url: str, symbolic: bool = False) -> Union[Chapter, N
width=0,
height=0))
return chapter

def set_config(self, **kwargs) -> None:
raise NotImplementedError('Manganato does not support set_config')

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_MANGANATO_GET_TTL_IN_SECONDS', 300)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_GET_TTL_IN_SECONDS', 300)),
max_size=20).cache
def get(self,
identifier: str,
Expand Down Expand Up @@ -163,14 +166,15 @@ def get(self,
return Manga(title=title,
authors=[Author(name=author)] if author is not None else None,
genres=[Genre(name=genre_name) for genre_name in genres],
url=urljoin(self.__BASE_URL, identifier),
id=identifier,
created_at=datetime.strptime(updated_at, "%b %d,%Y - %H:%M %p") if updated_at else None,
updated_at=datetime.strptime(updated_at, "%b %d,%Y - %H:%M %p") if updated_at else None,
thumbnail=Image(uri=cover), # type: ignore
cover=Image(uri=cover), # type: ignore
chapters=chapters) # type: ignore

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_MANGANATO_SEARCH_TTL_IN_SECONDS', 100)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_SEARCH_TTL_IN_SECONDS', 100)),
max_size=5).cache
def search(self,
query: str,
Expand All @@ -196,6 +200,7 @@ def search(self,

for result in results:
thumbs.append(Thumb(title=result.find('h3').text.replace('\n', '').strip(),
url=result.find('a', {'class': 'a-h text-nowrap item-title'})['href'],
cover=Image(uri=result.find('img')['src'], width=0, height=0),
id=result.find('a', {'class': 'a-h text-nowrap item-title'})['href'].split('/')[-1]))

Expand All @@ -204,7 +209,7 @@ def search(self,
total_pages=total_pages,
results=thumbs)

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_MANGANATO_PAGINATE_TTL_IN_SECONDS', 100)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_PAGINATE_TTL_IN_SECONDS', 100)),
max_size=5).cache
def paginate(self, page: int) -> Pagination:
response = self.__make_request(url=f'{self.__BASE_URL}/genre-all/{page}')
Expand All @@ -229,6 +234,7 @@ def paginate(self, page: int) -> Pagination:
info = cast(Tag, item.find('a', {'class': 'genres-item-img bookmark_check'}))
cover = info.find('img')
pagination.results.append(Thumb(id=info['href'].split('/')[-1], # type: ignore
url=info['href'],
title=info['title'] if info is not None else "",
cover=Image(uri=cover['src'], width=0, height=0))) # type: ignore

Expand All @@ -241,13 +247,10 @@ def paginate(self, page: int) -> Pagination:
def random(self) -> Manga:
raise NotImplementedError('Manganato does not support random')

def set_config(self, **kwargs) -> None:
raise NotImplementedError('Manganato does not support set_config')

def author_page(self, author: str, page: int) -> AuthorPage:
raise NotImplementedError('Manganato does not support author_page')

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_MANGANATO_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS', 100)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS', 100)),
max_size=20).cache
def fetch_chapter_by_symbolic_link(self, link: SymbolicLink) -> Chapter:
chapter = self.__create_chapter(url=link.link)
Expand Down
14 changes: 9 additions & 5 deletions enma/infra/adapters/repositories/nhentai.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def __make_page_uri(self,

return url

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_NHENTAI_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS', 100)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_FETCH_SYMBOLIC_LINK_TTL_IN_SECONDS', 100)),
max_size=20).cache
def fetch_chapter_by_symbolic_link(self,
link: SymbolicLink) -> Chapter:
Expand Down Expand Up @@ -156,7 +156,7 @@ def __create_chapter(self,
height=page.get('h')))
return chapter

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_NHENTAI_GET_TTL_IN_SECONDS', 300)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_GET_TTL_IN_SECONDS', 300)),
max_size=20).cache
def get(self,
identifier: str,
Expand Down Expand Up @@ -201,6 +201,7 @@ def get(self,
id=doujin.get('id'),
created_at=datetime.fromtimestamp(doujin.get('upload_date'), tz=timezone.utc),
updated_at=datetime.fromtimestamp(doujin.get('upload_date'), tz=timezone.utc),
url=urljoin(self.__BASE_URL, f'g/{doujin.get("id")}'),
language=language[0] if len(language) > 0 else None,
authors=authors,
genres=genres,
Expand All @@ -210,7 +211,7 @@ def get(self,

return manga

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_NHENTAI_SEARCH_TTL_IN_SECONDS', 100)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_SEARCH_TTL_IN_SECONDS', 100)),
max_size=5).cache
def search(self,
query: str,
Expand Down Expand Up @@ -279,6 +280,7 @@ def search(self,
caption = result_caption.text

thumbs.append(Thumb(id=doujin_id,
url=urljoin(self.__BASE_URL, f'g/{doujin_id}'),
cover=Image(uri=cover_uri or '',
mime=MIME.J,
width=int(width or 0),
Expand All @@ -291,7 +293,7 @@ def search(self,

return search_result

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_NHENTAI_PAGINATE_TTL_IN_SECONDS', 100)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_PAGINATE_TTL_IN_SECONDS', 100)),
max_size=5).cache
def paginate(self, page: int) -> Pagination:
response = self.__make_request(url=urljoin(self.__API_URL, f'galleries/all'),
Expand All @@ -308,6 +310,7 @@ def paginate(self, page: int) -> Pagination:
total_pages=PAGES,
results=[Thumb(id=result.get('id'),
title=result.get('title').get('english'),
url=urljoin(self.__BASE_URL, f'g/{result.get("id")}'),
cover=Image(uri=self.__make_page_uri(type='cover',
media_id=result.get('media_id'),
mime=MIME[result.get('images').get('cover').get('t').upper()]),
Expand Down Expand Up @@ -335,7 +338,7 @@ def random(self, retry=0) -> Manga:

return doujin

@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_NHENTAI_AUTHOR_TTL_IN_SECONDS', 100)),
@Cache(max_age_seconds=int(os.getenv('ENMA_CACHING_AUTHOR_TTL_IN_SECONDS', 100)),
max_size=5).cache
def author_page(self,
author: str,
Expand Down Expand Up @@ -394,6 +397,7 @@ def author_page(self,
caption = result_caption.text

thumbs.append(Thumb(id=doujin_id,
url=urljoin(self.__BASE_URL, f'g/{doujin_id}'),
cover=Image(uri=cover_uri or '',
mime=MIME.J,
width=int(width or 0),
Expand Down
Loading

0 comments on commit 57624af

Please sign in to comment.