Skip to content

Commit

Permalink
feat: add google drive as storage option
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexandreSenpai committed Nov 11, 2024
1 parent 1854a2c commit 210146a
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
"python.testing.pytestEnabled": true,
"python.analysis.autoImportCompletions": true
}
1 change: 1 addition & 0 deletions enma/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
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.google_drive import GoogleDriveStorage
from enma.infra.adapters.storage.local import LocalStorage
from enma.domain.entities.manga import Manga, Chapter, SymbolicLink
from enma.domain.entities.search_result import SearchResult
Expand Down
2 changes: 2 additions & 0 deletions enma/domain/entities/manga.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class ILanguage(TypedDict):
class Manga(Entity[IMangaProps]):
def __init__(self,
title: Title,
status: Literal['ongoing', 'completed'],
url: str,
chapters: Union[list[Chapter], None] = None,
language: Union[str, None] = None,
Expand All @@ -141,6 +142,7 @@ def __init__(self,
created_at=created_at,
updated_at=updated_at)

self.status = status
self.title = title
self.language = language
self.cover = cover
Expand Down
2 changes: 2 additions & 0 deletions enma/infra/adapters/repositories/mangadex.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,12 +345,14 @@ def __parse_full_manga(self,
thumbnail = self.__get_cover(manga_data.get('id'),
manga_data.get('relationships'))

status = 'completed' if attrs.get('status', "").lower() == 'completed' else 'ongoing'

manga = Manga(title=self.__get_title(alt_titles=attrs.get('altTitles'),
title=attrs.get('title', dict()).get('en') or ''),
id=manga_data.get('id'),
created_at=datetime.fromisoformat(attrs.get('createdAt')),
updated_at=datetime.fromisoformat(attrs.get('updatedAt')),
status=status,
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())),
Expand Down
9 changes: 6 additions & 3 deletions enma/infra/adapters/repositories/manganato.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,12 @@ def get(self,

if table_vals is None: return

title_cel, author_cel, _, genres_cel = table_vals
title_cel, author_cel, status_cel, genres_cel = table_vals
title = self.__create_title(main_title=elem_title,
alternative=title_cel.text)
author = author_cel.text.strip()
status = status_cel.text.strip().lower()

genres = genres_cel.text.replace('\n', '').split(' - ')

extra_infos = cast(Tag, soup.find('div', {'class': 'story-info-right-extent'}))
Expand All @@ -164,6 +166,7 @@ def get(self,
executor.shutdown()

return Manga(title=title,
status='completed' if status == 'completed' else 'ongoing',
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),
Expand Down Expand Up @@ -234,8 +237,8 @@ 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 "",
url=info['href'], # type: ignore
title=info['title'] if info is not None else "", # type: ignore
cover=Image(uri=cover['src'], width=0, height=0))) # type: ignore

last_pagination = soup.find('a', {'class': 'page-blue page-last'})
Expand Down
1 change: 1 addition & 0 deletions enma/infra/adapters/repositories/nhentai.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,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),
status='completed',
url=urljoin(self.__BASE_URL, f'g/{doujin.get("id")}'),
language=language[0] if len(language) > 0 else None,
authors=authors,
Expand Down
83 changes: 83 additions & 0 deletions enma/infra/adapters/storage/google_drive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
try:
from googleapiclient.discovery import build, HttpError
from googleapiclient.http import MediaIoBaseUpload
from google.oauth2.service_account import Credentials
except ImportError as e:
raise ImportError(
"The dependencies for Google Drive are not installed. "
"Please install them using 'pip install enma[google_drive]'."
) from e

from enma.application.core.interfaces.saver_adapter import File, ISaverAdapter

class GoogleDriveStorage(ISaverAdapter):

def __init__(
self,
credentials_path: str,
root_shared_folder: str):
self.credentials = Credentials.from_service_account_file(credentials_path)
self.service = build('drive', 'v3', credentials=self.credentials)
self.root_shared_folder = root_shared_folder

def save(self, path: str, file: File) -> bool:
try:
folder_id = self._get_or_create_folder(path)

file_metadata = {
'name': file.name,
'parents': [folder_id]
}

media = MediaIoBaseUpload(file.data, mimetype='application/octet-stream')

teste = self.service.files().create(
body=file_metadata,
media_body=media,
fields='id'
).execute()
print(teste)
return True
except HttpError as e:
print(f'Erro HTTP ao fazer upload: {e}')
return False
except Exception as e:
print(f'Erro ao fazer upload: {e}')
return False

def _get_or_create_folder(self, path: str) -> str:
folder_names = path.strip('/').split('/')
parent_id = self.root_shared_folder

for folder_name in folder_names:
query = (
f"name = '{folder_name}' and "
f"mimeType = 'application/vnd.google-apps.folder' and "
f"'{parent_id}' in parents and "
f"trashed = false"
)

results = self.service.files().list(
q=query,
spaces='drive',
fields='files(id, name)'
).execute()
items = results.get('files', [])

if items:
folder_id = items[0]['id']
else:
folder_metadata = {
'name': folder_name,
'mimeType': 'application/vnd.google-apps.folder',
'parents': [parent_id]
}
folder = self.service.files().create(
body=folder_metadata,
fields='id'
).execute()
folder_id = folder.get('id')

parent_id = folder_id

return parent_id
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ pydantic==2.8.2
pytest==8.3.2
expiringdict==1.2.2
pytest-cov==4.1.0
google-api-python-client>=2.0.0
google-auth-httplib2>=0.1.0
google-auth-oauthlib>=0.4.0
6 changes: 6 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ setup_requires =
[options.package_data]
enma = *.txt, *.rst, *.md

[options.extras_require]
google_drive =
google-api-python-client>=2.0.0
google-auth-httplib2>=0.1.0
google-auth-oauthlib>=0.4.0

[tool.setuptools_scm]
write_to = enma/_version.py

Expand Down

0 comments on commit 210146a

Please sign in to comment.