Skip to content

Commit

Permalink
Merge pull request #783 from meisnate12/develop
Browse files Browse the repository at this point in the history
v1.16.2
  • Loading branch information
meisnate12 authored Mar 16, 2022
2 parents 0671366 + a9eff11 commit 278a674
Show file tree
Hide file tree
Showing 27 changed files with 894 additions and 332 deletions.
9 changes: 3 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ jobs:
runs-on: ubuntu-latest
steps:

- name: Check Out Repo
uses: actions/checkout@v3

- name: Send Discord Release Notification
uses: bythope/discord-[email protected]
uses: nhevia/discord-styled-releases@main
with:
webhookUrl: ${{ secrets.RELEASE_WEBHOOK }}
handler: 'release'
webhook_id: ${{ secrets.RELEASE_WEBHOOK_ID }}
webhook_token: ${{ secrets.RELEASE_WEBHOOK_TOKEN }}
16 changes: 9 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
FROM python:3.9-slim
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
COPY . /
RUN echo "**** install system packages ****" \
&& apt-get update \
&& apt-get upgrade -y --no-install-recommends \
&& apt-get install -y tzdata --no-install-recommends \
&& apt-get install -y gcc g++ libxml2-dev libxslt-dev libz-dev
COPY requirements.txt /
RUN echo "**** install python packages ****" \
&& apt-get install -y gcc g++ libxml2-dev libxslt-dev libz-dev wget \
&& wget -O /tini https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-"$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
&& chmod +x /tini \
&& pip3 install --no-cache-dir --upgrade --requirement /requirements.txt \
&& apt-get autoremove -y \
&& apt-get --purge autoremove wget gcc g++ libxml2-dev libxslt-dev libz-dev -y \
&& apt-get clean \
&& apt-get update \
&& apt-get check \
&& apt-get -f install \
&& apt-get autoclean \
&& rm -rf /requirements.txt /tmp/* /var/tmp/* /var/lib/apt/lists/*
COPY . /
VOLUME /config
ENTRYPOINT ["/tini", "-s", "python3", "plex_meta_manager.py", "--"]
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.16.1
1.16.2
4 changes: 4 additions & 0 deletions docs/_static/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,8 @@ p {
}
.tab-set {
width: auto !important;
}
.highlighted {
background-color: #ac0ce3 !important;
color: #FFFFFF !important;
}
89 changes: 57 additions & 32 deletions docs/config/operations.md

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions docs/config/tmdb.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ tmdb:
language: en
```
| Attribute | Allowed Values | Default | Required |
|:-----------|:---------------------|:-------:|:--------:|
| `apikey` | User TMDb V3 API Key | N/A | ✅ |
| `language` | User Language | en | ❌ |
| Attribute | Allowed Values | Default | Required |
|:-------------------|:--------------------------------------------------------------------------|:-------:|:--------:|
| `apikey` | User TMDb V3 API Key | N/A | ✅ |
| `language` | User Language | en | ❌ |
| `cache_expiration` | Number of days before each cache mapping expires and has to be re-cached. | 60 | ❌ |

If you do not have a TMDb V3 API key please refer to this [guide](https://developers.themoviedb.org/3/getting-started/introduction).
28 changes: 27 additions & 1 deletion docs/metadata/builders/anilist.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ No configuration is required for these builders.
| [`anilist_relations`](#anilist-relations) | Finds the anime specified by the AniList ID and every relation in its relation tree except Character and Other relations | ✅ | ✅ | ❌ |
| [`anilist_studio`](#anilist-studio) | Finds all anime specified by the AniList Studio ID | ✅ | ✅ | ❌ |
| [`anilist_id`](#anilist-id) | Finds the anime specified by the AniList ID | ✅ | ✅ | ❌ |
| [`anilist_userlist`](#anilist-userlist) | Finds the anime in AniList User's Anime list the options are detailed below | ✅ | ✅ | ✅ |
| [`anilist_search`](#anilist-search) | Finds the anime specified by the AniList search parameters provided | ✅ | ✅ | ✅ |

## AniList Top Rated Anime
Expand Down Expand Up @@ -98,6 +99,31 @@ collections:
anilist_id: 23, 219
```

## AniList UserList

Gets anime in AniList User's Anime list. The different sub-attributes are detailed below.

Both `username` and `list_name` are required.

The `sync_mode: sync` and `collection_order: custom` Details are recommended since the lists are continuously updated and in a specific order.

| Attribute | Description |
|:------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `username` | **Description:** A user's AniList Username |
| `list_name` | **Description:** A user's AniList List Name |
| `sort_by` | **Description:** Sort Order to return<br>**Default:** `score`<br>**Values:**<table class="clearTable"><tr><td>`score`</td><td>Sort by User Score</td></tr><tr><td>`popularity`</td><td>Sort by Popularity</td></tr><tr><td>`status`</td><td>Sort by Status</td></tr><tr><td>`progress`</td><td>Sort by Progress</td></tr><tr><td>`last_updated`</td><td>Sort by Last Updated</td></tr><tr><td>`last_added`</td><td>Sort by Last Added</td></tr><tr><td>`start_date`</td><td>Sort by Start Date</td></tr><tr><td>`completed_date`</td><td>Sort by Completed Date</td></tr></table> |

```yaml
collections:
Currently Watching Anime:
anilist_userlist:
username: Username
list_name: Watching
sort_by: score
collection_order: custom
sync_mode: sync
```

## AniList Search

Finds the anime specified by the AniList Search the options are detailed below.
Expand Down Expand Up @@ -228,4 +254,4 @@ collections:
sort_by: popular
collection_order: custom
sync_mode: sync
```
```
4 changes: 4 additions & 0 deletions docs/metadata/dynamic.md
Original file line number Diff line number Diff line change
Expand Up @@ -1538,6 +1538,10 @@ dynamic_collections:

Name of the template to use for these dynamic collections. Each `type` has its own default template, but if you want to define and use your own template you can.

Each template is passed a template variable whose name matches the dynamic collection `type`. i.e. in the example below `<<network>>` is the template variable.

`key` and `key_name` are both passed along and can be used as template variables.

For example, the template below removes the limit on the `smart_filter` so it shows all items in each network

```yaml
Expand Down
2 changes: 1 addition & 1 deletion docs/metadata/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Tag filters can take multiple values as a **list or a comma-separated string**.
| `resolution` | Uses the resolution tag to match | &#9989; | &#10060; | &#10060; | &#9989; | &#10060; | &#10060; | &#10060; |
| `audio_language` | Uses the audio language tags to match | &#9989; | &#10060; | &#10060; | &#9989; | &#10060; | &#10060; | &#10060; |
| `subtitle_language` | Uses the subtitle language tags to match | &#9989; | &#10060; | &#10060; | &#9989; | &#10060; | &#10060; | &#10060; |
| `original_language`<sup>1</sup> | Uses TMDb original language [ISO 639-1 codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) to match<br>Example: `original_language: en, ko` | &#10060; | &#9989; | &#10060; | &#10060; | &#10060; | &#10060; | &#10060; |
| `original_language`<sup>1</sup> | Uses TMDb original language [ISO 639-1 codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) to match<br>Example: `original_language: en, ko` | &#10060; | &#9989; | &#9989; | &#10060; | &#10060; | &#10060; | &#10060; |
| `origin_country`<sup>1</sup> | Uses TMDb origin country [ISO 3166-1 alpha-2 codes](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) to match<br>Example: `origin_country: us` | &#10060; | &#9989; | &#10060; | &#10060; | &#10060; | &#10060; | &#10060; |
| `tmdb_status`<sup>1</sup> | Uses TMDb Status to match<br>**Values:** `returning`, `planned`, `production`, `ended`, `canceled`, `pilot` | &#10060; | &#9989; | &#10060; | &#10060; | &#10060; | &#10060; | &#10060; |
| `tmdb_type`<sup>1</sup> | Uses TMDb Type to match<br>**Values:** `documentary`, `news`, `production`, `miniseries`, `reality`, `scripted`, `talk_show`, `video` | &#10060; | &#9989; | &#10060; | &#10060; | &#10060; | &#10060; | &#10060; |
Expand Down
82 changes: 64 additions & 18 deletions modules/anidb.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import time
from datetime import datetime
from modules import util
from modules.util import Failed

Expand All @@ -14,9 +15,51 @@
"login": f"{base_url}/perl-bin/animedb.pl"
}

class AniDBObj:
def __init__(self, anidb, anidb_id, language):
self.anidb = anidb
self.anidb_id = anidb_id
self.language = language
response = self.anidb._request(f"{urls['anime']}/{anidb_id}", language=self.language)

def parse_page(xpath, is_list=False, is_float=False, is_date=False, fail=False):
parse_results = response.xpath(xpath)
try:
if len(parse_results) > 0:
parse_results = [r.strip() for r in parse_results if len(r) > 0]
if parse_results:
if is_list:
return parse_results
elif is_float:
return float(parse_results[0])
elif is_date:
return datetime.strptime(parse_results[0], "%d.%m.%Y")
else:
return parse_results[0]
except (ValueError, TypeError):
pass
if fail:
raise Failed(f"AniDB Error: No Anime Found for AniDB ID: {self.anidb_id}")
elif is_list:
return []
elif is_float:
return 0
else:
return None

self.official_title = parse_page(f"//th[text()='Main Title']/parent::tr/td/span/text()", fail=True)
self.title = parse_page(f"//th[text()='Official Title']/parent::tr/td/span/span/span[text()='{self.language}']/parent::span/parent::span/parent::td/label/text()")
self.rating = parse_page(f"//th[text()='Rating']/parent::tr/td/span/a/span/text()", is_float=True)
self.average = parse_page(f"//th[text()='Average']/parent::tr/td/span/a/span/text()", is_float=True)
self.released = parse_page(f"//th[text()='Year']/parent::tr/td/span/text()", is_date=True)
self.tags = [g.capitalize() for g in parse_page("//th/a[text()='Tags']/parent::th/parent::tr/td/span/a/span/text()", is_list=True)]
self.description = response.xpath(f"string(//div[@itemprop='description'])")


class AniDB:
def __init__(self, config):
def __init__(self, config, language):
self.config = config
self.language = language
self.username = None
self.password = None

Expand All @@ -29,46 +72,46 @@ def login(self, username, password):
if not self._request(urls["login"], data=data).xpath("//li[@class='sub-menu my']/@title"):
raise Failed("AniDB Error: Login failed")

def _request(self, url, language=None, data=None):
def _request(self, url, data=None):
if self.config.trace_mode:
logger.debug(f"URL: {url}")
if data:
return self.config.post_html(url, data=data, headers=util.header(language))
return self.config.post_html(url, data=data, headers=util.header(self.language))
else:
return self.config.get_html(url, headers=util.header(language))
return self.config.get_html(url, headers=util.header(self.language))

def _popular(self, language):
response = self._request(urls["popular"], language=language)
def _popular(self):
response = self._request(urls["popular"])
return util.get_int_list(response.xpath("//td[@class='name anime']/a/@href"), "AniDB ID")

def _relations(self, anidb_id, language):
response = self._request(f"{urls['anime']}/{anidb_id}{urls['relation']}", language=language)
def _relations(self, anidb_id):
response = self._request(f"{urls['anime']}/{anidb_id}{urls['relation']}")
return util.get_int_list(response.xpath("//area/@href"), "AniDB ID")

def _validate(self, anidb_id, language):
response = self._request(f"{urls['anime']}/{anidb_id}", language=language)
def _validate(self, anidb_id):
response = self._request(f"{urls['anime']}/{anidb_id}")
ids = response.xpath(f"//*[text()='a{anidb_id}']/text()")
if len(ids) > 0:
return util.regex_first_int(ids[0], "AniDB ID")
raise Failed(f"AniDB Error: AniDB ID: {anidb_id} not found")

def validate_anidb_ids(self, anidb_ids, language):
def validate_anidb_ids(self, anidb_ids):
anidb_list = util.get_int_list(anidb_ids, "AniDB ID")
anidb_values = []
for anidb_id in anidb_list:
try:
anidb_values.append(self._validate(anidb_id, language))
anidb_values.append(self._validate(anidb_id))
except Failed as e:
logger.error(e)
if len(anidb_values) > 0:
return anidb_values
raise Failed(f"AniDB Error: No valid AniDB IDs in {anidb_list}")

def _tag(self, tag, limit, language):
def _tag(self, tag, limit):
anidb_ids = []
current_url = f"{urls['tag']}/{tag}"
while True:
response = self._request(current_url, language=language)
response = self._request(current_url)
anidb_ids.extend(util.get_int_list(response.xpath("//td[@class='name main anime']/a/@href"), "AniDB ID"))
next_page_list = response.xpath("//li[@class='next']/a/@href")
if len(anidb_ids) >= limit or len(next_page_list) == 0:
Expand All @@ -77,20 +120,23 @@ def _tag(self, tag, limit, language):
current_url = f"{base_url}{next_page_list[0]}"
return anidb_ids[:limit]

def get_anidb_ids(self, method, data, language):
def get_anime(self, anidb_id):
return AniDBObj(self, anidb_id, self.language)

def get_anidb_ids(self, method, data):
anidb_ids = []
if method == "anidb_popular":
logger.info(f"Processing AniDB Popular: {data} Anime")
anidb_ids.extend(self._popular(language)[:data])
anidb_ids.extend(self._popular()[:data])
elif method == "anidb_tag":
logger.info(f"Processing AniDB Tag: {data['limit'] if data['limit'] > 0 else 'All'} Anime from the Tag ID: {data['tag']}")
anidb_ids = self._tag(data["tag"], data["limit"], language)
anidb_ids = self._tag(data["tag"], data["limit"])
elif method == "anidb_id":
logger.info(f"Processing AniDB ID: {data}")
anidb_ids.append(data)
elif method == "anidb_relation":
logger.info(f"Processing AniDB Relation: {data}")
anidb_ids.extend(self._relations(data, language))
anidb_ids.extend(self._relations(data))
else:
raise Failed(f"AniDB Error: Method {method} not supported")
logger.debug("")
Expand Down
Loading

0 comments on commit 278a674

Please sign in to comment.