mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-10 06:54:21 +00:00
[7] update mal auth
This commit is contained in:
parent
2df51e78ad
commit
681db1429f
7 changed files with 57 additions and 29 deletions
2
VERSION
2
VERSION
|
@ -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:
|
||||
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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
})
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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():
|
||||
|
|
Loading…
Reference in a new issue