diff --git a/.gitignore b/.gitignore index 8ba9e0e..3e37bb2 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,97 @@ env/ venv/ ENV/ env.bak/ -venv.bak/ \ No newline at end of file +venv.bak/ + +# Created by https://www.toptal.com/developers/gitignore/api/pycharm+all +# Edit at https://www.toptal.com/developers/gitignore?templates=pycharm+all + +### PyCharm+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +# End of https://www.toptal.com/developers/gitignore/api/pycharm+all \ No newline at end of file diff --git a/crunpyroll/enums/__init__.py b/crunpyroll/enums/__init__.py index 8a4a6cd..515ee96 100644 --- a/crunpyroll/enums/__init__.py +++ b/crunpyroll/enums/__init__.py @@ -1,3 +1,4 @@ from .content_type import ContentType from .image_type import ImageType -from .api_host import APIHost \ No newline at end of file +from .api_host import APIHost +from .sort_type import SortType diff --git a/crunpyroll/enums/sort_type.py b/crunpyroll/enums/sort_type.py new file mode 100644 index 0000000..8835ed9 --- /dev/null +++ b/crunpyroll/enums/sort_type.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class SortType(Enum): + """Sort type enumeration.""" + + NEWLY_ADDED = "newly_added" + "Sort by newly added contents" + + # TODO: Add others sort type diff --git a/crunpyroll/methods/__init__.py b/crunpyroll/methods/__init__.py index 33069fd..70ff713 100644 --- a/crunpyroll/methods/__init__.py +++ b/crunpyroll/methods/__init__.py @@ -1,4 +1,5 @@ from .search import Search +from .browse import Browse from .get_index import GetIndex from .get_profile import GetProfile from .get_series import GetSeries @@ -11,8 +12,10 @@ from .get_old_streams import GetOldStreams from .delete_active_stream import DeleteActiveStream + class Methods( Search, + Browse, GetIndex, GetProfile, GetSeries, @@ -25,4 +28,4 @@ class Methods( GetObjects, DeleteActiveStream ): - pass \ No newline at end of file + pass diff --git a/crunpyroll/methods/browse.py b/crunpyroll/methods/browse.py new file mode 100644 index 0000000..7c1f84a --- /dev/null +++ b/crunpyroll/methods/browse.py @@ -0,0 +1,61 @@ +from crunpyroll import enums +from crunpyroll import types +from crunpyroll.utils import get_date +from datetime import datetime +from typing import List + +import crunpyroll + + +class Browse: + async def browse( + self: "crunpyroll.Client", + sort_by: "enums.SortType" = enums.SortType.NEWLY_ADDED, + date: datetime = get_date(), + max_results: int = 15, + locale: str = None, + preferred_audio_language: str = None, + filter: "enums.ContentType" = enums.ContentType.EPISODE + ) -> "types.BrowseQuery": + """ + Browse for series movies or episodes. + + Parameters: + date: (``datetime``, *optional*): + Get only contents release at this date + Default date: current + sort_by: (Value of :obj:`~crunpyroll.enums.SortType`, *optional*): + Sort content + Default to newly added :obj:`~crunpyroll.enums.NEWLY_ADDED`. + max_results (``int``, *optional*): + Max results for every content type. + Default to 15 + locale (``str``, *optional*): + Localize request for different results. + Default to the one used in Client. + preferred_audio_language (``str``, *optional*): + Preferred audio language + Default to the one used in Client. + filter (:obj:`~crunpyroll.enums.ContentType`, *optional*): + Content to filter. (Several filters cannot be used at the same time) + Default to enums.ContentType.EPISODE in :obj:`~crunpyroll.enums.ContentType`. + + Returns: + :obj:`~crunpyroll.types.BrowseQuery`: + On success, query of results is returned. + """ + await self.session.retrieve() + + response = await self.api_request( + method="GET", + endpoint="content/v2/discover/browse", + params={ + "n": max_results, + "locale": locale or self.locale, + "preferred_audio_language": preferred_audio_language or self.preferred_audio_language, + "type": filter.value, + "sort_by": sort_by.value + } + ) + + return types.BrowseQuery.parse(date, response) diff --git a/crunpyroll/types/__init__.py b/crunpyroll/types/__init__.py index f65dde1..7c58952 100644 --- a/crunpyroll/types/__init__.py +++ b/crunpyroll/types/__init__.py @@ -3,6 +3,7 @@ from .episodes import EpisodesQuery, Episode from .movies import Movie from .search import SearchQuery +from .browse import BrowseQuery from .images import Image, Images from .cms import CMS from .index import SessionIndex diff --git a/crunpyroll/types/browse.py b/crunpyroll/types/browse.py new file mode 100644 index 0000000..4e07e60 --- /dev/null +++ b/crunpyroll/types/browse.py @@ -0,0 +1,44 @@ +from ..enums import ContentType +from ..utils import str_to_date + +from .obj import Object +from .series import Series +from .episodes import Episode +from .movies import Movie + +from typing import Union, List, Dict +from datetime import datetime + +ITEMS_TYPING = List[Union["Series", "Episode", "Movie"]] + + +class BrowseQuery(Object): + """ + Query containing browse results. + + Parameters: + total (``int``): + Total results returned. + + items (List of [:obj:`~crunpyroll.types.Series` | :obj:`~crunpyroll.types.Episode` | :obj:`~crunpyroll.types.Movie`]): + List containing each result. + """ + + def __init__(self, total: int, items: List): + self.total: int = total + self.items: ITEMS_TYPING = items + + @classmethod + def parse(cls, date: datetime, response: Dict): + items = [] + for item in response["data"]: + if str_to_date(item['last_public']).date() == date.date(): + if item["type"] == ContentType.SERIES.value: + items.append(Series.parse(item)) + elif item["type"] == ContentType.EPISODE.value: + if str_to_date(item['last_public']).date() == date.date(): + items.append(Episode.parse(item)) + elif item["type"] == ContentType.MOVIE.value: + items.append(Movie.parse(item)) + + return cls(len(items), items) diff --git a/setup.py b/setup.py index 403b37b..2174242 100644 --- a/setup.py +++ b/setup.py @@ -17,5 +17,5 @@ }, install_requires=["httpx", "xmltodict"], packages=setuptools.find_packages(), - python_requires=">=3.7", + python_requires=">=3.10", ) \ No newline at end of file