1
- from urllib .request import Request , urlopen
2
- import sys
3
1
import os
2
+ import sys
4
3
import json
5
4
import re
6
- import urllib .error
7
- import urllib .request
5
+ import unicodedata # For Unicode normalization
6
+ from urllib .parse import quote # For URL encoding
7
+ from urllib .request import Request , urlopen # For HTTP requests
8
+ import urllib .error # For handling URL-related errors
8
9
9
10
# to import from a parent directory we need to add that directory to the system path
10
11
csd = os .path .dirname (
35
36
"You need to download the folder 'py_common' from the community repo! (CommunityScrapers/tree/master/scrapers/py_common)" ,
36
37
file = sys .stderr )
37
38
sys .exit ()
39
+
38
40
import config
39
41
40
42
SHOKO_API_KEY = '' #leave empty it gets your Shoko api key with your shoko server username and password
43
45
SHOKO_PASS = config .SHOKO .get ("pass" , "" )
44
46
45
47
46
-
47
48
def validate_user_inputs () -> bool :
48
49
shoko = bool (re .search (r"^(http|https)://.+:\d+$" , SHOKO_URL ))
49
50
if shoko is False :
@@ -61,8 +62,10 @@ def get_filename(scene_id: str) -> str:
61
62
pattern = "(^.+)([\\ \\ ]|[/])"
62
63
replace = ""
63
64
filename = re .sub (pattern , replace , str (path ))
64
- log .debug (f"encoded filename: { filename } " )
65
- return filename
65
+ normalized_filename = unicodedata .normalize ('NFC' , filename )
66
+ encoded_filename = quote (normalized_filename , safe = '' )
67
+ log .debug (f"encoded filename: { encoded_filename } " )
68
+ return encoded_filename
66
69
67
70
68
71
def find_scene_id (scene_id : str ) -> (str , str ):
@@ -85,15 +88,17 @@ def lookup_scene(scene_id: str, epnumber: str, apikey: str, date: str) -> dict:
85
88
res ['date' ] = date
86
89
res ['tags' ] = [{"name" : i } for i in tags ]
87
90
88
- # Convert the string to a ScrapedStudio instance
89
- studio : ScrapedStudio = {
90
- "name" : studio , # only the name will get imported
91
- "image" : f"{ SHOKO_URL } /api/v3/Image/AniDB/Staff/{ studio_id } "
92
- # image will not be imported because of a bug in Stash right now
93
- # this will work as soon as that is fixed
94
- }
91
+ if studio is None or studio_id is None :
92
+ log .info ("No studio information found. Skipping studio." )
93
+ else :
94
+ # Convert the string to a ScrapedStudio instance
95
+ studio : ScrapedStudio = {
96
+ "name" : studio , # Map the string to the required `name` field
97
+ "image" : f"{ SHOKO_URL } /api/v3/Image/AniDB/Staff/{ studio_id } "
98
+ }
95
99
96
- res ['studio' ] = studio
100
+ res ['studio' ] = studio
101
+
97
102
log .debug ("sceneinfo from Shoko: " + str (res ))
98
103
return res
99
104
@@ -149,26 +154,42 @@ def get_series(apikey: str, scene_id: str):
149
154
headers ["apikey" ] = apikey
150
155
request = Request (SHOKO_URL + '/api/serie/fromep?id=' + scene_id , headers = headers )
151
156
152
- response_body = urlopen (request ).read ()
153
- json_object = json .loads (response_body .decode ('utf-8' ))
157
+ try :
158
+ response_body = urlopen (request ).read ()
159
+ json_object = json .loads (response_body .decode ('utf-8' ))
160
+ except Exception as e :
161
+ log .error (f"Failed to fetch series details: { e } " )
162
+ return None , None , None , None , None , None
163
+
154
164
log .debug ("got series:\t " + str (json_object ))
155
- title = json_object [ 'name' ]
156
- details = json_object [ 'summary' ]
157
- local_sizes = json_object [ 'local_sizes' ][ 'Episodes' ]
165
+ title = json_object . get ( 'name' , None )
166
+ details = json_object . get ( 'summary' , None )
167
+ local_sizes = json_object . get ( 'local_sizes' , {}). get ( 'Episodes' , 0 )
158
168
log .debug ("number of episodes " + str (local_sizes ))
159
169
cover = SHOKO_URL + json_object ['art' ]['thumb' ][0 ]['url' ]
160
- tags = json_object ['tags' ]
161
-
162
- series_id = json_object ['id' ]
163
- response = requests .get (SHOKO_URL + '/api/v3/Series/%s/Cast?roleType=Studio' % series_id , headers = headers )
170
+ tags = json_object .get ('tags' , [])
164
171
165
- # Parse the JSON response
166
- json_response = response .json ()
172
+ series_id = json_object .get ('id' )
173
+
174
+ try :
175
+ response = requests .get (
176
+ f'{ SHOKO_URL } /api/v3/Series/{ series_id } /Cast?roleType=Studio' ,
177
+ headers = headers
178
+ )
179
+ response .raise_for_status ()
180
+ json_response = response .json ()
181
+ except requests .RequestException as e :
182
+ log .error (f"Failed to fetch studio data: { e } " )
183
+ json_response = []
184
+
185
+ # Handle cases where there are no studios
186
+ if json_response :
187
+ studio = json_response [0 ].get ('Staff' , {}).get ('Name' , None )
188
+ studio_id = json_response [0 ].get ('Staff' , {}).get ('ID' , None )
189
+ else :
190
+ studio = None
191
+ studio_id = None
167
192
168
- # Extract the 'Name' field
169
- studio = json_response [0 ]['Staff' ]['Name' ]
170
- studio_id = json_response [0 ]['Staff' ]['ID' ]
171
-
172
193
return title , details , cover , tags , studio , studio_id #, characters
173
194
174
195
0 commit comments