[7] update mal auth

pull/946/head
meisnate12 2 years ago
parent 2df51e78ad
commit 681db1429f

@ -1 +1 @@
1.17.1-develop6 1.17.1-develop7

@ -9,6 +9,7 @@ Below is a `mal` mapping example and the full set of attributes:
mal: mal:
client_id: ################################ client_id: ################################
client_secret: ################################################################ client_secret: ################################################################
localhost_url:
authorization: authorization:
access_token: access_token:
token_type: token_type:
@ -20,6 +21,7 @@ mal:
|:----------------|:--------------------------------------|:--------:| |:----------------|:--------------------------------------|:--------:|
| `client_id` | MyAnimeList Application Client ID | ✅ | | `client_id` | MyAnimeList Application Client ID | ✅ |
| `client_secret` | MyAnimeList Application Client Secret | ✅ | | `client_secret` | MyAnimeList Application Client Secret | ✅ |
| `localhost_url` | MyAnimeList Authorization URL | ❌ |
* All other attributes will be filled in by the script. * All other attributes will be filled in by the script.
@ -37,6 +39,20 @@ mal:
11. You should see `Successfully registered.` followed by a link that says `Return to list` click this link. 11. You should see `Successfully registered.` followed by a link that says `Return to list` click this link.
12. On this page Click the `Edit` button next to the application you just created. 12. On this page Click the `Edit` button next to the application you just created.
13. Record the `Client ID` and `Client Secret` found on the application page. 13. Record the `Client ID` and `Client Secret` found on the application page.
14. Go to this URL but replace `CLIENT_ID` with your Client ID `https://myanimelist.net/v1/oauth2/authorize?response_type=code&client_id=CLIENT_ID&code_challenge=k_UHwN_eHAPQVXiceC-rYGkozKqrJmKxPUIUOBIKo1noq_4XGRVCViP_dGcwB-fkPql8f56mmWj5aWCa2HDeugf6sRvnc9Rjhbb1vKGYLY0IwWsDNXRqXdksaVGJthux`
15. You should see a page that looks like this
![MAL Details](mal.png)
Click "Allow"
16. You will be taken to a page that will not load. That's fine and expected.
![Localhost Failure](localhost-fail.png)
17. Copy the URL, which will be `localhost/?code=BLAH` and paste in your config file next to `localhost_url`.
NOTE: If you do not see an error as above but instead get taken to some seemingly random website, you probably have a webserver running on your local computer, probably from some sort of tutorial if you don't recall having set one up. For example, some Docker tutorials have you start up local web servers.
You will need to stop that web server while you're doing this in order to grab that localhost URL.
18. Run PMM and the auth will be completed.
### Alternative Way Letting PMM make the URL
You can record just your `client_id` and `client_secret` and pmm will create the url for you described below.
* On the first run, the script will walk the user through the OAuth flow by producing a MyAnimeList URL for the user to follow. After following the URL login to MyAnimeList.net and authorize the application by clicking the `Allow` button which will redirect the user to `http://localhost/`. Copy the entire URL and paste it into the script and if the URL is correct then the script will populate the `authorization` sub-attributes to use in subsequent runs. * On the first run, the script will walk the user through the OAuth flow by producing a MyAnimeList URL for the user to follow. After following the URL login to MyAnimeList.net and authorize the application by clicking the `Allow` button which will redirect the user to `http://localhost/`. Copy the entire URL and paste it into the script and if the URL is correct then the script will populate the `authorization` sub-attributes to use in subsequent runs.

@ -129,15 +129,15 @@ Each metadata requires its own section within the `metadata` attribute. Each ite
```yaml ```yaml
metadata: metadata:
Godzilla vs. Mechagodzilla II: Godzilla vs. Mechagodzilla II:
# ... details to change for this itwm # ... details to change for this item
Godzilla vs. Megaguirus: Godzilla vs. Megaguirus:
# ... details to change for this itwm # ... details to change for this item
Godzilla vs. Megalon: Godzilla vs. Megalon:
# ... details to change for this itwm # ... details to change for this item
Halloween (Rob Zombie): Halloween (Rob Zombie):
# ... details to change for this itwm # ... details to change for this item
etc: etc:
# ... details to change for this itwm # ... details to change for this item
``` ```
### Title & Year ### Title & Year

@ -748,6 +748,9 @@ class CollectionBuilder:
self.details["collection_mode"] = "hide" self.details["collection_mode"] = "hide"
self.sync = True self.sync = True
if self.smart_url:
self.sync = False
self.do_missing = not self.config.no_missing and (self.details["show_missing"] or self.details["save_report"] self.do_missing = not self.config.no_missing and (self.details["show_missing"] or self.details["save_report"]
or (self.library.Radarr and self.radarr_details["add_missing"]) or (self.library.Radarr and self.radarr_details["add_missing"])
or (self.library.Sonarr and self.sonarr_details["add_missing"])) or (self.library.Sonarr and self.sonarr_details["add_missing"]))
@ -2635,7 +2638,7 @@ class CollectionBuilder:
self.library.delete_user_playlist(self.obj.title, user) self.library.delete_user_playlist(self.obj.title, user)
except NotFound: except NotFound:
pass pass
new_playlist = self.obj.copyToUser(user) self.obj.copyToUser(user)
logger.info(f"Playlist: {self.name} synced to {user}") logger.info(f"Playlist: {self.name} synced to {user}")
def send_notifications(self, playlist=False): def send_notifications(self, playlist=False):

@ -460,6 +460,7 @@ class ConfigFile:
self.MyAnimeList = MyAnimeList(self, { self.MyAnimeList = MyAnimeList(self, {
"client_id": check_for_attribute(self.data, "client_id", parent="mal", throw=True), "client_id": check_for_attribute(self.data, "client_id", parent="mal", throw=True),
"client_secret": check_for_attribute(self.data, "client_secret", parent="mal", throw=True), "client_secret": check_for_attribute(self.data, "client_secret", parent="mal", throw=True),
"localhost_url": check_for_attribute(self.data, "localhost_url", parent="mal", default_is_none=True),
"config_path": self.config_path, "config_path": self.config_path,
"authorization": self.data["mal"]["authorization"] if "authorization" in self.data["mal"] else None "authorization": self.data["mal"]["authorization"] if "authorization" in self.data["mal"] else None
}) })

@ -41,6 +41,7 @@ search_sorts = ["mal_id", "title", "type", "rating", "start_date", "end_date", "
search_combos = [f"{s}.{d}" for s in search_sorts for d in ["desc", "asc"]] search_combos = [f"{s}.{d}" for s in search_sorts for d in ["desc", "asc"]]
base_url = "https://api.myanimelist.net/v2/" base_url = "https://api.myanimelist.net/v2/"
jiken_base_url = "https://api.jikan.moe/v4/" jiken_base_url = "https://api.jikan.moe/v4/"
uni_code_verifier = "k_UHwN_eHAPQVXiceC-rYGkozKqrJmKxPUIUOBIKo1noq_4XGRVCViP_dGcwB-fkPql8f56mmWj5aWCa2HDeugf6sRvnc9Rjhbb1vKGYLY0IwWsDNXRqXdksaVGJthux"
urls = { urls = {
"oauth_token": "https://myanimelist.net/v1/oauth2/token", "oauth_token": "https://myanimelist.net/v1/oauth2/token",
"oauth_authorize": "https://myanimelist.net/v1/oauth2/authorize", "oauth_authorize": "https://myanimelist.net/v1/oauth2/authorize",
@ -55,6 +56,7 @@ class MyAnimeList:
self.config = config self.config = config
self.client_id = params["client_id"] self.client_id = params["client_id"]
self.client_secret = params["client_secret"] self.client_secret = params["client_secret"]
self.localhost_url = params["localhost_url"]
self.config_path = params["config_path"] self.config_path = params["config_path"]
self.authorization = params["authorization"] self.authorization = params["authorization"]
logger.secret(self.client_secret) logger.secret(self.client_secret)
@ -85,17 +87,21 @@ class MyAnimeList:
return self._studios return self._studios
def _authorization(self): def _authorization(self):
code_verifier = secrets.token_urlsafe(100)[:128] if self.localhost_url:
url = f"{urls['oauth_authorize']}?response_type=code&client_id={self.client_id}&code_challenge={code_verifier}" code_verifier = uni_code_verifier
logger.info("") url = self.localhost_url
logger.info(f"Navigate to: {url}") else:
logger.info("") code_verifier = secrets.token_urlsafe(100)[:128]
logger.info("Login and click the Allow option. You will then be redirected to a localhost") url = f"{urls['oauth_authorize']}?response_type=code&client_id={self.client_id}&code_challenge={code_verifier}"
logger.info("url that most likely won't load, which is fine. Copy the URL and paste it below") logger.info("")
webbrowser.open(url, new=2) logger.info(f"Navigate to: {url}")
try: url = util.logger_input("URL").strip() logger.info("")
except TimeoutExpired: raise Failed("Input Timeout: URL required.") logger.info("Login and click the Allow option. You will then be redirected to a localhost")
if not url: raise Failed("MyAnimeList Error: No input MyAnimeList code required.") logger.info("url that most likely won't load, which is fine. Copy the URL and paste it below")
webbrowser.open(url, new=2)
try: url = util.logger_input("URL").strip()
except TimeoutExpired: raise Failed("Input Timeout: URL required.")
if not url: raise Failed("MyAnimeList Error: No input MyAnimeList code required.")
match = re.search("code=([^&]+)", str(url)) match = re.search("code=([^&]+)", str(url))
if not match: if not match:
raise Failed("MyAnimeList Error: Invalid URL") raise Failed("MyAnimeList Error: Invalid URL")

@ -237,17 +237,19 @@ class DataFile:
else: else:
return og_txt return og_txt
for i in range(2): for i in range(4):
for option in optional: if i == 2:
if option not in variables and f"<<{option}>>" in str(final_data): for dm, dd in default.items():
raise Failed final_data = scan_text(final_data, dm, dd)
for variable, variable_data in variables.items(): else:
if (variable == "collection_name" or variable == "playlist_name") and _method in ["radarr_tag", "item_radarr_tag", "sonarr_tag", "item_sonarr_tag"]: for option in optional:
final_data = scan_text(final_data, variable, variable_data.replace(",", "")) if option not in variables and f"<<{option}>>" in str(final_data):
elif variable != "name": raise Failed
final_data = scan_text(final_data, variable, variable_data) for variable, variable_data in variables.items():
for dm, dd in default.items(): if (variable == "collection_name" or variable == "playlist_name") and _method in ["radarr_tag", "item_radarr_tag", "sonarr_tag", "item_sonarr_tag"]:
final_data = scan_text(final_data, dm, dd) final_data = scan_text(final_data, variable, variable_data.replace(",", ""))
elif variable != "name":
final_data = scan_text(final_data, variable, variable_data)
return final_data return final_data
for method_name, attr_data in template.items(): for method_name, attr_data in template.items():

Loading…
Cancel
Save