node build fixed
This commit is contained in:
249
seanime-2.9.10/internal/manga/providers/comick_multi.go
Normal file
249
seanime-2.9.10/internal/manga/providers/comick_multi.go
Normal file
@@ -0,0 +1,249 @@
|
||||
package manga_providers
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"fmt"
|
||||
"net/url"
|
||||
hibikemanga "seanime/internal/extension/hibike/manga"
|
||||
"seanime/internal/util"
|
||||
"seanime/internal/util/comparison"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/imroc/req/v3"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
type (
|
||||
ComicKMulti struct {
|
||||
Url string
|
||||
Client *req.Client
|
||||
logger *zerolog.Logger
|
||||
}
|
||||
)
|
||||
|
||||
func NewComicKMulti(logger *zerolog.Logger) *ComicKMulti {
|
||||
client := req.C().
|
||||
SetUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36").
|
||||
SetTimeout(60 * time.Second).
|
||||
EnableInsecureSkipVerify().
|
||||
ImpersonateSafari()
|
||||
|
||||
return &ComicKMulti{
|
||||
Url: "https://api.comick.fun",
|
||||
Client: client,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// DEVNOTE: Each chapter ID is a unique string provided by ComicK
|
||||
|
||||
func (c *ComicKMulti) GetSettings() hibikemanga.Settings {
|
||||
return hibikemanga.Settings{
|
||||
SupportsMultiScanlator: true,
|
||||
SupportsMultiLanguage: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ComicKMulti) Search(opts hibikemanga.SearchOptions) ([]*hibikemanga.SearchResult, error) {
|
||||
|
||||
c.logger.Debug().Str("query", opts.Query).Msg("comick: Searching manga")
|
||||
|
||||
searchUrl := fmt.Sprintf("%s/v1.0/search?q=%s&limit=25&page=1", c.Url, url.QueryEscape(opts.Query))
|
||||
if opts.Year != 0 {
|
||||
searchUrl += fmt.Sprintf("&from=%d&to=%d", opts.Year, opts.Year)
|
||||
}
|
||||
|
||||
var data []*ComicKResultItem
|
||||
resp, err := c.Client.R().
|
||||
SetSuccessResult(&data).
|
||||
Get(searchUrl)
|
||||
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msg("comick: Failed to send request")
|
||||
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
|
||||
if !resp.IsSuccessState() {
|
||||
c.logger.Error().Str("status", resp.Status).Msg("comick: Request failed")
|
||||
return nil, fmt.Errorf("failed to reach API: status %s", resp.Status)
|
||||
}
|
||||
|
||||
results := make([]*hibikemanga.SearchResult, 0)
|
||||
for _, result := range data {
|
||||
|
||||
// Skip fan-colored manga
|
||||
if strings.Contains(result.Slug, "fan-colored") {
|
||||
continue
|
||||
}
|
||||
|
||||
var coverURL string
|
||||
if len(result.MdCovers) > 0 && result.MdCovers[0].B2Key != "" {
|
||||
coverURL = "https://meo.comick.pictures/" + result.MdCovers[0].B2Key
|
||||
}
|
||||
|
||||
altTitles := make([]string, len(result.MdTitles))
|
||||
for j, title := range result.MdTitles {
|
||||
altTitles[j] = title.Title
|
||||
}
|
||||
|
||||
// DEVNOTE: We don't compare to alt titles because ComicK's synonyms aren't good
|
||||
compRes, _ := comparison.FindBestMatchWithSorensenDice(&opts.Query, []*string{&result.Title})
|
||||
|
||||
results = append(results, &hibikemanga.SearchResult{
|
||||
ID: result.HID,
|
||||
Title: cmp.Or(result.Title, result.Slug),
|
||||
Synonyms: altTitles,
|
||||
Image: coverURL,
|
||||
Year: result.Year,
|
||||
SearchRating: compRes.Rating,
|
||||
Provider: ComickProvider,
|
||||
})
|
||||
}
|
||||
|
||||
if len(results) == 0 {
|
||||
c.logger.Warn().Msg("comick: No results found")
|
||||
return nil, ErrNoChapters
|
||||
}
|
||||
|
||||
c.logger.Info().Int("count", len(results)).Msg("comick: Found results")
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (c *ComicKMulti) FindChapters(id string) ([]*hibikemanga.ChapterDetails, error) {
|
||||
ret := make([]*hibikemanga.ChapterDetails, 0)
|
||||
|
||||
// c.logger.Debug().Str("mangaId", id).Msg("comick: Fetching chapters")
|
||||
|
||||
uri := fmt.Sprintf("%s/comic/%s/chapters?page=0&limit=1000000&chap-order=1", c.Url, id)
|
||||
c.logger.Debug().Str("mangaId", id).Str("uri", uri).Msg("comick: Fetching chapters")
|
||||
|
||||
var data struct {
|
||||
Chapters []*ComicChapter `json:"chapters"`
|
||||
}
|
||||
|
||||
resp, err := c.Client.R().
|
||||
SetSuccessResult(&data).
|
||||
Get(uri)
|
||||
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msg("comick: Failed to send request")
|
||||
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
|
||||
if !resp.IsSuccessState() {
|
||||
c.logger.Error().Str("status", resp.Status).Msg("comick: Request failed")
|
||||
return nil, fmt.Errorf("failed to decode response: status %s", resp.Status)
|
||||
}
|
||||
|
||||
chapters := make([]*hibikemanga.ChapterDetails, 0)
|
||||
chaptersCountMap := make(map[string]int)
|
||||
for _, chapter := range data.Chapters {
|
||||
if chapter.Chap == "" {
|
||||
continue
|
||||
}
|
||||
title := "Chapter " + chapter.Chap + " "
|
||||
|
||||
if title == "" {
|
||||
if chapter.Title == "" {
|
||||
title = "Oneshot"
|
||||
} else {
|
||||
title = chapter.Title
|
||||
}
|
||||
}
|
||||
title = strings.TrimSpace(title)
|
||||
|
||||
groupName := ""
|
||||
if len(chapter.GroupName) > 0 {
|
||||
groupName = chapter.GroupName[0]
|
||||
}
|
||||
|
||||
count, ok := chaptersCountMap[groupName]
|
||||
if !ok {
|
||||
chaptersCountMap[groupName] = 0
|
||||
count = 0
|
||||
}
|
||||
chapters = append(chapters, &hibikemanga.ChapterDetails{
|
||||
Provider: ComickProvider,
|
||||
ID: chapter.HID,
|
||||
Title: title,
|
||||
Language: chapter.Lang,
|
||||
Index: uint(count),
|
||||
URL: fmt.Sprintf("%s/chapter/%s", c.Url, chapter.HID),
|
||||
Chapter: chapter.Chap,
|
||||
Scanlator: groupName,
|
||||
Rating: 0,
|
||||
UpdatedAt: chapter.UpdatedAt,
|
||||
})
|
||||
chaptersCountMap[groupName]++
|
||||
}
|
||||
|
||||
// Sort chapters by index
|
||||
slices.SortStableFunc(chapters, func(i, j *hibikemanga.ChapterDetails) int {
|
||||
return cmp.Compare(i.Index, j.Index)
|
||||
})
|
||||
|
||||
ret = append(ret, chapters...)
|
||||
|
||||
if len(ret) == 0 {
|
||||
c.logger.Warn().Msg("comick: No chapters found")
|
||||
return nil, ErrNoChapters
|
||||
}
|
||||
|
||||
c.logger.Info().Int("count", len(ret)).Msg("comick: Found chapters")
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (c *ComicKMulti) FindChapterPages(id string) ([]*hibikemanga.ChapterPage, error) {
|
||||
ret := make([]*hibikemanga.ChapterPage, 0)
|
||||
|
||||
c.logger.Debug().Str("chapterId", id).Msg("comick: Finding chapter pages")
|
||||
|
||||
uri := fmt.Sprintf("%s/chapter/%s", c.Url, id)
|
||||
|
||||
var data struct {
|
||||
Chapter *ComicChapter `json:"chapter"`
|
||||
}
|
||||
|
||||
resp, err := c.Client.R().
|
||||
SetHeader("User-Agent", util.GetRandomUserAgent()).
|
||||
SetSuccessResult(&data).
|
||||
Get(uri)
|
||||
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msg("comick: Failed to send request")
|
||||
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
|
||||
if !resp.IsSuccessState() {
|
||||
c.logger.Error().Str("status", resp.Status).Msg("comick: Request failed")
|
||||
return nil, fmt.Errorf("failed to decode response: status %s", resp.Status)
|
||||
}
|
||||
|
||||
if data.Chapter == nil {
|
||||
c.logger.Error().Msg("comick: Chapter not found")
|
||||
return nil, fmt.Errorf("chapter not found")
|
||||
}
|
||||
|
||||
for index, image := range data.Chapter.MdImages {
|
||||
ret = append(ret, &hibikemanga.ChapterPage{
|
||||
Provider: ComickProvider,
|
||||
URL: fmt.Sprintf("https://meo.comick.pictures/%s", image.B2Key),
|
||||
Index: index,
|
||||
Headers: make(map[string]string),
|
||||
})
|
||||
}
|
||||
|
||||
if len(ret) == 0 {
|
||||
c.logger.Warn().Msg("comick: No pages found")
|
||||
return nil, ErrNoPages
|
||||
}
|
||||
|
||||
c.logger.Info().Int("count", len(ret)).Msg("comick: Found pages")
|
||||
|
||||
return ret, nil
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user