diff --git a/.gitea/changelog-config.json b/.gitea/changelog-config.json new file mode 100644 index 0000000..5a7d4e7 --- /dev/null +++ b/.gitea/changelog-config.json @@ -0,0 +1,103 @@ +{ + "categories": [ + { + "title": "## ๐Ÿš€ Features", + "labels": [ + "add", + "Add", + "Kind/Feature", + "feat", + "Feature", + "Feat" + ] + }, + { + "title": "## ๐Ÿงฐ Enhancements", + "labels": [ + "enhancement", + "Enhancement", + "Kind/Enhancement", + "improvement", + "Improvement", + "Kind/Improvement" + ] + }, + { + "title": "## ๐Ÿ› Fixes", + "labels": [ + "fix", + "Fix", + "Kind/Bug", + "Kind/Security" + ] + }, + { + "title": "## ๐Ÿงช Upgrade", + "labels": ["upgrade","Upgrade","Clean"] + } + , + { + "title": "## ๐Ÿ“ Documentation", + "labels": ["docs","Docs", "Kind/Documentation"] + }, + { + "title": "## ๐Ÿ› ๏ธ Maintenance", + "labels": [ + "maintenance", + "Maintenance", + "Kind/Maintenance", + "chore", + "Chore", + "Kind/Chore" + ] + }, + { + "title": "## โช Reverts", + "labels": [ + "revert", + "Revert", + "Kind/Revert", + "Kind/Reverts", + "reverts", + "Reverts" + ] + }, + { + "title": "## ๐Ÿ—‘๏ธ Deprecation", + "labels": ["deprecation","Deprecation", "Kind/Deprecation"] + }, + { + "title": "## โšก๏ธ Performance Improvements", + "labels": [ + "perf", + "Perf", + "Kind/Performance" + ] + }, + { + "title": "## ๐ŸŽจ Styling", + "labels": [ + "style", + "Style", + "Kind/Style" + ] + }, + { + "title": "## ๐ŸŽฏ Other Changes", + "labels": [] + } + ], + "label_extractor": [ + { + "pattern": "(\\w+) (.+)", + "target": "$1", + "on_property": "title" + } + ], + "sort": "ASC", + "template": "${{CHANGELOG}}", + "pr_template": "- ${{TITLE}}\n - PR: #${{NUMBER}}", + "empty_template": "- no changes", + "max_pull_requests": 1000, + "max_back_track_time_days": 1000 +} \ No newline at end of file diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index a77bb37..dfb5148 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -25,10 +25,15 @@ jobs: steps: - name: Checkout code uses: actions/checkout@master + with: + fetch-depth: 0 + fetch-tags: true - name: Install uv uses: astral-sh/setup-uv@v5 - name: Set up Python run: uv python install + with: + python-version-file: "pyproject.toml" - name: Set Git identity run: | git config user.name "Gitea CI" @@ -47,14 +52,16 @@ jobs: with: github_token: ${{ secrets.GITHUB_TOKEN }} branch: ${{ github.ref }} - - - name: Create release notes - run: | - mkdir release_notes - echo -e "${{ inputs.release_notes }}" >> release_notes/release_notes.md - echo "Release notes:" - cat release_notes/release_notes.md - echo "" + - name: Build Changelog + id: build_changelog + uses: https://github.com/mikepenz/release-changelog-builder-action@v5 + with: + platform: "gitea" + baseURL: "http://192.168.178.110:3000" + configuration: ".gitea/changelog_config.json" + + env: + GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }} - name: Build package run: uv build - name: Publish package @@ -66,15 +73,15 @@ jobs: - name: Create release id: create_release if: ${{ github.event.inputs.github_release == 'true' }} - uses: softprops/action-gh-release@master with: - tag_name: ${{ env.VERSION }} - release_name: Release ${{ env.VERSION }} - body_path: release_notes/release_notes.md + tag_name: v${{ env.VERSION }} + release_name: Release v${{ env.VERSION }} + body: ${{steps.build_changelog.outputs.changelog}} draft: false prerelease: false make_latest: true files: | dist/* env: - GITHUB_TOKEN: ${{ secrets.TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} diff --git a/pyproject.toml b/pyproject.toml index a50b091..72228fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,10 @@ requires = ["hatchling"] build-backend = "hatchling.build" [dependency-groups] -test = ["pytest>=8.3.4"] +test = [ + "pytest>=8.3.4", + "pytest-cov>=6.2.1", +] [tool.pytest.ini_options] testpaths = ["tests"] diff --git a/src/anilistapi/__init__.py b/src/anilistapi/__init__.py index 9be8555..cdbc3b7 100644 --- a/src/anilistapi/__init__.py +++ b/src/anilistapi/__init__.py @@ -2,4 +2,5 @@ from importlib.metadata import version __version__ = version("anilistapi") __contact__ = "coding_contact@pm.me" -from .api import AnilistAPI +__all__ = ["AnilistAPI", "MediaFormat"] +from .api import AnilistAPI, MediaFormat diff --git a/src/anilistapi/api.py b/src/anilistapi/api.py index eff2728..74c34b2 100644 --- a/src/anilistapi/api.py +++ b/src/anilistapi/api.py @@ -1,19 +1,37 @@ -import requests -from .schemas.manga import Manga, Tag -from .queries.manga import ( - MANGA_QUERY, - MANGA_ID_QUERY, - REQUESTS_QUERY, - GENRES_QUERY, - TAGS_QUERY, -) -from limit import limit -from anilistapi import __version__, __contact__ import os import time +from enum import Enum -REQUEST_LIMIT = 90 -REQUEST_PERIOD = 60 +import requests +from limit import limit + +from anilistapi import __contact__, __version__ + +from .queries.manga import ( + GENRES_QUERY, + ID_QUERY, + REQUESTS_QUERY, + TAGS_QUERY, +) +from .schemas.manga import Manga, Tag + +REQUEST_LIMIT = 1 +REQUEST_PERIOD = 1 + + +class MediaFormat(str, Enum): + MANGA = "MANGA" + NOVEL = "NOVEL" + ONE_SHOT = "ONE_SHOT" + TV = "TV" + TV_SHORT = "TV_SHORT" + MOVIE = "MOVIE" + OVA = "OVA" + ONA = "ONA" + MUSIC = "MUSIC" + SPECIAL = "SPECIAL" + + # add a function to get class AnilistAPI: @@ -25,16 +43,24 @@ class AnilistAPI: @limit(REQUEST_LIMIT, REQUEST_PERIOD) def request(self, query: str, variables: dict) -> dict: url = "https://graphql.anilist.co" - response = requests.post(url, json={"query": query, "variables": variables}) - time.sleep(1) - if response.status_code != 200: + try: + response = requests.post(url, json={"query": query, "variables": variables}) + time.sleep(1) + if response.status_code != 200: + return {} + # raise Exception(f"Error: {response}, response: {response.json()}, query: {query}, variables: {variables}") + return response.json() + except: return {} - # raise Exception(f"Error: {response}, response: {response.json()}, query: {query}, variables: {variables}") - return response.json() - def search_manga(self, search: str) -> list[Manga]: - variables = {"search": search, "format": "MANGA"} - response = self.request(REQUESTS_QUERY, variables) + def search_manga(self, search: str, format: MediaFormat) -> list[Manga]: + variables = {"search": search, "format": format, "type": "MANGA"} + try: + response = self.request(REQUESTS_QUERY, variables) + except: + time.sleep(15) + return self.search_manga(search, format) + # check if reponse has data Page and media if not response.get("data", {}).get("Page", {}).get("media"): return [] @@ -44,15 +70,17 @@ class AnilistAPI: return res def get_manga(self, id: int) -> Manga: + if str(id).isnumeric(): + id = int(id) assert isinstance(id, int), "id must be an integer" variables = {"id": id} - response = self.request(MANGA_ID_QUERY, variables) + response = self.request(ID_QUERY, variables) if not response.get("data", {}).get("Media"): return None return Manga(**response["data"]["Media"]) - def kompage_search(self, search: str) -> list[Manga]: - variables = {"search": search} + def kompage_search(self, search: str, format: MediaFormat) -> list[Manga]: + variables = {"search": search, "format": format, "type": "MANGA"} response = self.request(REQUESTS_QUERY, variables) # check if reponse has data Page and media if not response.get("data", {}).get("Page", {}).get("media"): diff --git a/src/anilistapi/queries/manga.py b/src/anilistapi/queries/manga.py index 500ce2f..d74a0c3 100644 --- a/src/anilistapi/queries/manga.py +++ b/src/anilistapi/queries/manga.py @@ -1,5 +1,5 @@ -MANGA_QUERY = """ -query media($search: String) { +QUERY = """ +query media($search: String, $type: MediaType) { Page { pageInfo { hasNextPage @@ -8,7 +8,7 @@ Page { currentPage lastPage } - media(type: MANGA, search: $search) { + media(type: $type, search: $search) { id title { romaji @@ -21,9 +21,9 @@ Page { } """ -MANGA_ID_QUERY = """ +ID_QUERY = """ query media($id: Int) { # Define which variables will be used in the query (id) -Media (type: MANGA, id:$id) { # Insert our variables into the query arguments (id) +Media (id:$id) { # Insert our variables into the query arguments (id) id title { romaji @@ -53,11 +53,12 @@ Media (type: MANGA, id:$id) { # Insert our variables into the query arguments (i type } countryOfOrigin + siteUrl } } """ -REQUESTS_QUERY = """query query($search: String, $genres:[String], $tags:[String], $format: MediaFormat) { +REQUESTS_QUERY = """query query($search: String, $genres:[String], $tags:[String], $format: MediaFormat, $type: MediaType) { Page(perPage: 100) { pageInfo { hasNextPage @@ -66,7 +67,7 @@ Page(perPage: 100) { currentPage lastPage } - media(type: MANGA, search: $search, genre_in: $genres, tag_in: $tags, sort: SEARCH_MATCH, format: $format) { + media(type: $type, search: $search, genre_in: $genres, tag_in: $tags, sort: SEARCH_MATCH, format: $format) { id title { romaji @@ -102,8 +103,8 @@ Page(perPage: 100) { } }""" -REQUESTED_QUERY = """query query($search: Int) { -Media(type: MANGA, id: $search, sort: SEARCH_MATCH) { +REQUESTED_QUERY = """query query($search: Int, $type: MediaType) { +Media(type: $type, id: $search, sort: SEARCH_MATCH) { id title { romaji diff --git a/src/anilistapi/schemas/manga.py b/src/anilistapi/schemas/manga.py index c1bef8d..947e8ae 100644 --- a/src/anilistapi/schemas/manga.py +++ b/src/anilistapi/schemas/manga.py @@ -44,3 +44,7 @@ class Manga: @property def isLightNovel(self): return self.format == "NOVEL" + + @property + def name(self): + return self.title.__repr__() diff --git a/src/anilistapi/schemas/title.py b/src/anilistapi/schemas/title.py index 8e29102..5317906 100644 --- a/src/anilistapi/schemas/title.py +++ b/src/anilistapi/schemas/title.py @@ -8,10 +8,11 @@ class Title: native: str = None def __repr__(self): - return self.english if self.english else self.native + return self.english if self.english else self.romaji if self.romaji else self.native + def __str__(self): - return self.english if self.english else self.native + return self.english if self.english else self.romaji if self.romaji else self.native @property def alternateTitles(self):