[7] update mal auth

This commit is contained in:
meisnate12 2022-07-04 02:49:52 -04:00
parent 2df51e78ad
commit 681db1429f
7 changed files with 57 additions and 29 deletions

View file

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

View file

@ -9,6 +9,7 @@ Below is a `mal` mapping example and the full set of attributes:
mal:
client_id: ################################
client_secret: ################################################################
localhost_url:
authorization:
access_token:
token_type:
@ -20,6 +21,7 @@ mal:
|:----------------|:--------------------------------------|:--------:|
| `client_id` | MyAnimeList Application Client ID | ✅ |
| `client_secret` | MyAnimeList Application Client Secret | ✅ |
| `localhost_url` | MyAnimeList Authorization URL | ❌ |
* 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.
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.
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.

View file

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

View file

@ -748,6 +748,9 @@ class CollectionBuilder:
self.details["collection_mode"] = "hide"
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"]
or (self.library.Radarr and self.radarr_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)
except NotFound:
pass
new_playlist = self.obj.copyToUser(user)
self.obj.copyToUser(user)
logger.info(f"Playlist: {self.name} synced to {user}")
def send_notifications(self, playlist=False):

View file

@ -460,6 +460,7 @@ class ConfigFile:
self.MyAnimeList = MyAnimeList(self, {
"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),
"localhost_url": check_for_attribute(self.data, "localhost_url", parent="mal", default_is_none=True),
"config_path": self.config_path,
"authorization": self.data["mal"]["authorization"] if "authorization" in self.data["mal"] else None
})

View file

@ -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"]]
base_url = "https://api.myanimelist.net/v2/"
jiken_base_url = "https://api.jikan.moe/v4/"
uni_code_verifier = "k_UHwN_eHAPQVXiceC-rYGkozKqrJmKxPUIUOBIKo1noq_4XGRVCViP_dGcwB-fkPql8f56mmWj5aWCa2HDeugf6sRvnc9Rjhbb1vKGYLY0IwWsDNXRqXdksaVGJthux"
urls = {
"oauth_token": "https://myanimelist.net/v1/oauth2/token",
"oauth_authorize": "https://myanimelist.net/v1/oauth2/authorize",
@ -55,6 +56,7 @@ class MyAnimeList:
self.config = config
self.client_id = params["client_id"]
self.client_secret = params["client_secret"]
self.localhost_url = params["localhost_url"]
self.config_path = params["config_path"]
self.authorization = params["authorization"]
logger.secret(self.client_secret)
@ -85,17 +87,21 @@ class MyAnimeList:
return self._studios
def _authorization(self):
code_verifier = secrets.token_urlsafe(100)[:128]
url = f"{urls['oauth_authorize']}?response_type=code&client_id={self.client_id}&code_challenge={code_verifier}"
logger.info("")
logger.info(f"Navigate to: {url}")
logger.info("")
logger.info("Login and click the Allow option. You will then be redirected to a localhost")
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.")
if self.localhost_url:
code_verifier = uni_code_verifier
url = self.localhost_url
else:
code_verifier = secrets.token_urlsafe(100)[:128]
url = f"{urls['oauth_authorize']}?response_type=code&client_id={self.client_id}&code_challenge={code_verifier}"
logger.info("")
logger.info(f"Navigate to: {url}")
logger.info("")
logger.info("Login and click the Allow option. You will then be redirected to a localhost")
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))
if not match:
raise Failed("MyAnimeList Error: Invalid URL")

View file

@ -237,17 +237,19 @@ class DataFile:
else:
return og_txt
for i in range(2):
for option in optional:
if option not in variables and f"<<{option}>>" in str(final_data):
raise Failed
for variable, variable_data in variables.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, variable, variable_data.replace(",", ""))
elif variable != "name":
final_data = scan_text(final_data, variable, variable_data)
for dm, dd in default.items():
final_data = scan_text(final_data, dm, dd)
for i in range(4):
if i == 2:
for dm, dd in default.items():
final_data = scan_text(final_data, dm, dd)
else:
for option in optional:
if option not in variables and f"<<{option}>>" in str(final_data):
raise Failed
for variable, variable_data in variables.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, variable, variable_data.replace(",", ""))
elif variable != "name":
final_data = scan_text(final_data, variable, variable_data)
return final_data
for method_name, attr_data in template.items():