refactor: reduce graphqlRequestWithHash complexity
This commit is contained in:
@@ -318,17 +318,7 @@ func (c *AllAnimeProvider) graphqlRequest(ctx context.Context, query string, var
|
|||||||
const episodeQueryHash = "d405d0edd690624b66baba3068e0edc3ac90f1597d898a1ec8db4e5c43c00fec"
|
const episodeQueryHash = "d405d0edd690624b66baba3068e0edc3ac90f1597d898a1ec8db4e5c43c00fec"
|
||||||
|
|
||||||
func (c *AllAnimeProvider) graphqlRequestWithHash(ctx context.Context, showID, episode, mode string) (map[string]any, error) {
|
func (c *AllAnimeProvider) graphqlRequestWithHash(ctx context.Context, showID, episode, mode string) (map[string]any, error) {
|
||||||
mode = strings.ToLower(mode)
|
req, err := newEpisodeHashRequest(ctx, showID, episode, mode)
|
||||||
|
|
||||||
varsJSON := fmt.Sprintf(`{"showId":"%s","translationType":"%s","episodeString":"%s"}`, showID, mode, episode)
|
|
||||||
extJSON := fmt.Sprintf(`{"persistedQuery":{"version":1,"sha256Hash":"%s"}}`, episodeQueryHash)
|
|
||||||
|
|
||||||
params := url.Values{}
|
|
||||||
params.Set("variables", varsJSON)
|
|
||||||
params.Set("extensions", extJSON)
|
|
||||||
apiURL := fmt.Sprintf("%s/api?%s", allAnimeBaseURL, params.Encode())
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create GET request: %w", err)
|
return nil, fmt.Errorf("create GET request: %w", err)
|
||||||
}
|
}
|
||||||
@@ -352,13 +342,9 @@ func (c *AllAnimeProvider) graphqlRequestWithHash(ctx context.Context, showID, e
|
|||||||
return nil, fmt.Errorf("GET status %d: %s", statusCode, string(respBody))
|
return nil, fmt.Errorf("GET status %d: %s", statusCode, string(respBody))
|
||||||
}
|
}
|
||||||
|
|
||||||
var parsed map[string]any
|
parsed, err := parseGraphQLResponse(respBody, "decode response")
|
||||||
if err := json.Unmarshal(respBody, &parsed); err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("decode response: %w", err)
|
return nil, err
|
||||||
}
|
|
||||||
|
|
||||||
if errs, ok := parsed["errors"].([]any); ok && len(errs) > 0 {
|
|
||||||
return nil, fmt.Errorf("graphql error: %v", errs[0])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data, ok := parsed["data"].(map[string]any)
|
data, ok := parsed["data"].(map[string]any)
|
||||||
@@ -366,53 +352,148 @@ func (c *AllAnimeProvider) graphqlRequestWithHash(ctx context.Context, showID, e
|
|||||||
return nil, fmt.Errorf("no data in response")
|
return nil, fmt.Errorf("no data in response")
|
||||||
}
|
}
|
||||||
|
|
||||||
var toBeParsed string
|
decrypted, err := responseFromTobeparsed(data)
|
||||||
if s, ok := data["tobeparsed"].(string); ok && s != "" {
|
if err != nil {
|
||||||
toBeParsed = s
|
return nil, err
|
||||||
} else if episodeData, ok := data["episode"].(map[string]any); ok {
|
}
|
||||||
if s, ok := episodeData["tobeparsed"].(string); ok {
|
if decrypted != nil {
|
||||||
toBeParsed = s
|
return decrypted, nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if toBeParsed != "" {
|
if hasEpisodeSourceURLs(data) {
|
||||||
decrypted, err := decryptTobeparsed(toBeParsed)
|
return parsed, nil
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("decrypt tobeparsed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var ep map[string]any
|
|
||||||
if jerr := json.Unmarshal(decrypted, &ep); jerr != nil {
|
|
||||||
return nil, fmt.Errorf("unmarshal decrypted: %w", jerr)
|
|
||||||
}
|
|
||||||
|
|
||||||
var sourceURLs []any
|
|
||||||
if srcs, ok := ep["sourceUrls"].([]any); ok {
|
|
||||||
sourceURLs = srcs
|
|
||||||
} else if epInner, ok := ep["episode"].(map[string]any); ok {
|
|
||||||
if srcs, ok := epInner["sourceUrls"].([]any); ok {
|
|
||||||
sourceURLs = srcs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sourceURLs) > 0 {
|
|
||||||
return map[string]any{
|
|
||||||
"episode": map[string]any{
|
|
||||||
"sourceUrls": sourceURLs,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if episodeData, ok := data["episode"].(map[string]any); ok {
|
|
||||||
if srcs, ok := episodeData["sourceUrls"].([]any); ok && len(srcs) > 0 {
|
|
||||||
return parsed, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("no usable data in response")
|
return nil, fmt.Errorf("no usable data in response")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newEpisodeHashRequest(ctx context.Context, showID, episode, mode string) (*http.Request, error) {
|
||||||
|
varsJSON := fmt.Sprintf(`{"showId":"%s","translationType":"%s","episodeString":"%s"}`, showID, strings.ToLower(mode), episode)
|
||||||
|
extJSON := fmt.Sprintf(`{"persistedQuery":{"version":1,"sha256Hash":"%s"}}`, episodeQueryHash)
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("variables", varsJSON)
|
||||||
|
params.Set("extensions", extJSON)
|
||||||
|
|
||||||
|
return http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/api?%s", allAnimeBaseURL, params.Encode()), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGraphQLResponse(respBody []byte, decodeErrPrefix string) (map[string]any, error) {
|
||||||
|
var parsed map[string]any
|
||||||
|
if err := json.Unmarshal(respBody, &parsed); err != nil {
|
||||||
|
return nil, fmt.Errorf("%s: %w", decodeErrPrefix, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if errs, ok := parsed["errors"].([]any); ok && len(errs) > 0 {
|
||||||
|
return nil, fmt.Errorf("graphql error: %v", errs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func responseFromTobeparsed(data map[string]any) (map[string]any, error) {
|
||||||
|
toBeParsed := firstNonEmptyString(
|
||||||
|
nestedString(data, "tobeparsed"),
|
||||||
|
nestedString(data, "episode", "tobeparsed"),
|
||||||
|
)
|
||||||
|
if toBeParsed == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted, err := decryptTobeparsed(toBeParsed)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("decrypt tobeparsed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed, err := parseGraphQLResponse(decrypted, "unmarshal decrypted")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceURLs := firstNonEmptySlice(
|
||||||
|
nestedSlice(parsed, "sourceUrls"),
|
||||||
|
nestedSlice(parsed, "episode", "sourceUrls"),
|
||||||
|
)
|
||||||
|
if len(sourceURLs) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]any{
|
||||||
|
"episode": map[string]any{
|
||||||
|
"sourceUrls": sourceURLs,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasEpisodeSourceURLs(data map[string]any) bool {
|
||||||
|
return len(nestedSlice(data, "episode", "sourceUrls")) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func firstNonEmptyString(values ...string) string {
|
||||||
|
for _, value := range values {
|
||||||
|
if value != "" {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func firstNonEmptySlice(values ...[]any) []any {
|
||||||
|
for _, value := range values {
|
||||||
|
if len(value) > 0 {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func nestedString(data map[string]any, path ...string) string {
|
||||||
|
value, ok := nestedValue(data, path...)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
str, ok := value.(string)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
func nestedSlice(data map[string]any, path ...string) []any {
|
||||||
|
value, ok := nestedValue(data, path...)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
slice, ok := value.([]any)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
|
func nestedValue(data map[string]any, path ...string) (any, bool) {
|
||||||
|
var current any = data
|
||||||
|
for _, key := range path {
|
||||||
|
currentMap, ok := current.(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
current, ok = currentMap[key]
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return current, true
|
||||||
|
}
|
||||||
|
|
||||||
// GetEpisodeSources fetches stream URLs for a given show, episode, and mode (dub/sub).
|
// GetEpisodeSources fetches stream URLs for a given show, episode, and mode (dub/sub).
|
||||||
func (c *AllAnimeProvider) GetEpisodeSources(ctx context.Context, showID string, episode string, mode string) ([]StreamSource, error) {
|
func (c *AllAnimeProvider) GetEpisodeSources(ctx context.Context, showID string, episode string, mode string) ([]StreamSource, error) {
|
||||||
episodeQuery := `query($showId: String!, $translationType: VaildTranslationTypeEnumType!, $episodeString: String!) {
|
episodeQuery := `query($showId: String!, $translationType: VaildTranslationTypeEnumType!, $episodeString: String!) {
|
||||||
|
|||||||
Reference in New Issue
Block a user