Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ NEW SOURCE ] Mangadex #70

Merged
merged 14 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.10.6
3.12.0
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Enma",
"type": "debugpy",
"request": "launch",
"program": "/home/alexandresenpai/scripts/Enma/main.py",
"console": "integratedTerminal"
}
]
}
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"python.analysis.typeCheckingMode": "basic",
"cloudcode.duetAI.inlineSuggestions.enableAuto": false
"cloudcode.duetAI.inlineSuggestions.enableAuto": false,
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
36 changes: 27 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

Enma is a Python library designed to fetch manga and doujinshi data from many sources. It provides a unified interface to interact with different manga repositories, making it easier to retrieve manga details, search for manga, paginate through results, and fetch random manga.

## :warning: Warning
> **:exclamation: Important: Enma is not intended for mass querying or placing heavy loads on supported sources. Please use responsibly, adhering to the terms of service of the data sources. Misuse may result in service disruption or access denial.**

## Requirements

- Python 3.9+
Expand All @@ -41,17 +44,20 @@ except AssertionError:
raise RuntimeError(f"{package_name!r} requires Python {python_major}.{python_minor}+ (You have Python {sys.version})")
```

## Documentation
You can consult full Enma documentation at <strong><a href="https://enma.gitbook.io/enma" target="_blank">https://enma.gitbook.io/enma</a></strong>.

## Features Comparison

Feature | NHentai | Manganato
-----------|---------|-----------
search | ✅ | ✅
random | ✅ | 🚫
get | ✅ | ✅
paginate | ✅ | ✅
download | ✅ | ✅
author_page| ✅ | 🚫
set_config | ✅ | 🚫
Feature | NHentai | Manganato | Mangadex
-----------|---------|-----------|-----------
search | ✅ | ✅ | ✅
random | ✅ | 🚫 | ✅
get | ✅ | ✅ | ✅
paginate | ✅ | ✅ | ✅
download | ✅ | ✅ | ✅
author_page| ✅ | 🚫 | 🚫
set_config | ✅ | 🚫 | 🚫

## Usage

Expand Down Expand Up @@ -256,6 +262,18 @@ We welcome contributions! If you'd like to contribute:

Ensure you follow the coding standards and write tests for new features.

## Disclaimer

This software is provided "as is", without warranty of any kind, express or implied. The developers and contributors of the Enma library shall not be liable for any misuse, damages, or other consequences arising from the use of this software.

It is important to emphasize that the Enma library was developed with the goal of facilitating efficient and responsible access and manipulation of data. We do not encourage or support the use of this tool for conducting mass queries or accesses that could overload, harm, or in any way negatively affect the servers or services of the supported sources.

Users of the Enma library must always follow the guidelines, terms of use, and limitations imposed by the accessed data sources. We strongly recommend the implementation of responsible rate limiting practices and obtaining appropriate permissions when necessary, to ensure that the use of the library complies with all applicable laws and regulations, in addition to respecting ethical principles of data use.

By using the Enma library, you agree to use the tool in an ethical and responsible manner, acknowledging that the developers of Enma will not be responsible for any use that violates these guidelines.

We remind you that respect for the services and APIs of the supported sources is fundamental for the sustainability and longevity of both the Enma and the services used. We value the community and the development ecosystem and encourage all users to contribute to a safer, more respectful, and collaborative digital environment.

## License

MIT
8 changes: 5 additions & 3 deletions enma/__init__.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import sys
from enma.application.core.utils.logger import LogMode, logger
from enma.application.use_cases.download_chapter import Threaded
from enma.infra.entrypoints.lib import Enma, SourcesEnum, DefaultAvailableSources
from enma.infra.adapters.repositories.nhentai import CloudFlareConfig, NHentai, Sort
from enma.infra.entrypoints.lib import Enma, SourcesEnum
from enma.infra.adapters.repositories.nhentai import CloudFlareConfig, NHentai, Sort as NHentaiSort
from enma.infra.adapters.repositories.mangadex import Mangadex, Sort as MangadexSort
from enma.infra.adapters.repositories.manganato import Manganato
from enma.infra.adapters.downloaders.default import DefaultDownloader
from enma.infra.adapters.downloaders.manganato import ManganatoDownloader
from enma.application.core.interfaces.downloader_adapter import IDownloaderAdapter
from enma.application.core.interfaces.saver_adapter import ISaverAdapter
from enma.infra.adapters.storage.local import LocalStorage
from enma.domain.entities.manga import Manga
from enma.domain.entities.manga import Manga, Chapter, SymbolicLink
from enma.domain.entities.search_result import SearchResult
from enma.domain.entities.pagination import Pagination
from enma.domain.entities.author_page import AuthorPage
from enma.application.core.interfaces.manga_repository import IMangaRepository

package_name = "enma"
python_major = "3"
Expand Down
2 changes: 1 addition & 1 deletion enma/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '2.3.0'
__version__ = '2.4.0'
35 changes: 34 additions & 1 deletion enma/application/core/handlers/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,30 @@ def __init__(self, message: str) -> None:
self.desc: str = 'This error occurs when the client chooses nonexistent source.'
self.critical: bool = False

class Unknown(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)

self.code: str = 'UNKNOWN'
self.desc: str = 'This error occours when was not possible to determine the error root cause.'
self.critical: bool = True

class NotFound(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)

self.code: str = 'NOT_FOUND'
self.desc: str = 'This error occours when was not possible to find the requested resource.'
self.critical: bool = True

class Forbidden(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)

self.code: str = 'FORBIDDEN'
self.desc: str = 'This error occours when the client can\'t perform a request to the source due lack of credentials.'
self.critical: bool = True

class InvalidRequest(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)
Expand Down Expand Up @@ -67,4 +91,13 @@ def __init__(self, message: str) -> None:
self.message: str = message
self.code: str = 'EXCEED_RETRY_COUNT'
self.desc: str = 'This error occurs when enma tries perform some action but something went wrong.'
self.critical: bool = True
self.critical: bool = True

class ExceedRateLimit(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)

self.message: str = message
self.code: str = 'EXCEED_RATE_EXCEED'
self.desc: str = 'This error occurs when enma perform more requests than a server can handle. Cool down your requests to this source!'
self.critical: bool = False
15 changes: 8 additions & 7 deletions enma/application/use_cases/get_manga.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Union

from pydantic import BaseModel, Field, validator
from enma.application.core.handlers.error import InvalidRequest
from enma.application.core.handlers import error
from enma.application.core.interfaces.manga_repository import IMangaRepository
from enma.application.core.interfaces.use_case import DTO, IUseCase
from enma.application.core.utils.logger import logger
Expand All @@ -24,9 +24,10 @@ def __init__(self, manga_repository: IMangaRepository):
def execute(self, dto: DTO[GetMangaRequestDTO]) -> GetMangaResponseDTO:
logger.info(f'Fetching manga with identifier: {dto.data.identifier}.')

manga = self.__manga_repository.get(identifier=dto.data.identifier,
with_symbolic_links=dto.data.with_symbolic_links)

if manga is None: return GetMangaResponseDTO(found=False, manga=None)

return GetMangaResponseDTO(found=True, manga=manga)
try:
manga = self.__manga_repository.get(identifier=dto.data.identifier,
with_symbolic_links=dto.data.with_symbolic_links)
return GetMangaResponseDTO(found=True, manga=manga)
except error.NotFound:
logger.error(f'Could not find the manga using the provided identifier: {dto.data.identifier}')
return GetMangaResponseDTO(found=False, manga=None)
6 changes: 3 additions & 3 deletions enma/domain/entities/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import datetime
import json
from typing import Generic, TypeVar, Union
from uuid import uuid4

T = TypeVar('T')

Expand All @@ -23,12 +23,12 @@ def __init__(self,
"""Initializes an Entity with given or default values.

Args:
id: A Union of int, str, and None representing the entity's ID. Defaults to 0.
id: A Union of int, str, and None representing the entity's ID. Defaults to uuidv4.
created_at: A Union of datetime and None representing when the entity was created. Defaults to current UTC time.
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 0
self.id = id if id is not None else 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()

Expand Down
60 changes: 59 additions & 1 deletion enma/domain/entities/manga.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import TypedDict, Union
from typing import Literal, TypedDict, Union

from enma.domain.entities.base import Entity

class MIME(Enum):
JPG = 'jpg'
J = 'jpg'
PNG = 'png'
P = 'png'
GIF = 'gif'
G = 'gif'


@dataclass
class Image:
Expand Down Expand Up @@ -59,6 +63,55 @@ class Genre:
class Author(Genre):
...

class ILanguage(TypedDict):
ja: Literal['japanese']
jp: Literal['japanese']
japanese: Literal['japanese']
portuguese: Literal['portuguese']
pt: Literal['portuguese']
pt_br: Literal['portuguese']
english: Literal['english']
en: Literal['english']
en_us: Literal['english']
chinese: Literal['chinese']
cn: Literal['chinese']
zh: Literal['chinese']
russian: Literal['russian']
ru: Literal['russian']
turkish: Literal['turkish']
tr: Literal['turkish']
spanish: Literal['spanish']
es_la: Literal['spanish']
malay: Literal['malay']
ms: Literal['malay']
korean: Literal['korean']
ko: Literal['korean']

Language: ILanguage = {
'ja': 'japanese',
'jp': 'japanese',
'japanese': 'japanese',
'portuguese': 'portuguese',
'pt': 'portuguese',
'pt_br': 'portuguese',
'english': 'english',
'en': 'english',
'en_us': 'english',
'chinese': 'chinese',
'cn': 'chinese',
'zh': 'chinese',
'ru': 'russian',
'russian': 'russian',
'turkish': 'turkish',
'tr': 'turkish',
'spanish': 'spanish',
'es_la': 'spanish',
'malay': 'malay',
'ms': 'malay',
'korean': 'korean',
'ko': 'korean'
}

class Manga(Entity[IMangaProps]):
def __init__(self,
title: Title,
Expand All @@ -85,3 +138,8 @@ def __init__(self,
self.chapters = chapters or []

self.chapters_count = len(self.chapters if self.chapters else [])

def add_chapter(self,
chapter: Chapter):
self.chapters.append(chapter)
self.chapters_count += 1
Loading
Loading