Naming refactor. Added comments.

This commit is contained in:
Felipe M 2021-02-13 12:49:16 +01:00
parent a3cf924918
commit fc0e662409
Signed by: fmartingr
GPG Key ID: 716BC147715E716F
4 changed files with 61 additions and 22 deletions

View File

@ -11,15 +11,18 @@ import (
var cacheEnabled bool = true
// EnableCache enables request caching for reads
func EnableCache() {
cacheEnabled = true
}
// DisableCache disables cache reads
func DisableCache() {
cacheEnabled = false
}
func getCachePath() string {
// getBaseCachePath returns the base path for the cache storage
func getBaseCachePath() string {
userCacheDir, errCache := os.UserCacheDir()
if errCache != nil {
logrus.Fatalf("Unable to retrieve cache directory: %s", errCache)
@ -27,25 +30,30 @@ func getCachePath() string {
return filepath.Join(userCacheDir, "go-mangadex")
}
func getCachePathFor(mangadexURL *url.URL) string {
// getCachePath returns the absolute path to the files cache for the provided URL
func getCachePath(mangadexURL *url.URL) string {
fileName := getCacheFilename(mangadexURL)
return filepath.Join(getCachePath(), fileName)
return filepath.Join(getBaseCachePath(), fileName)
}
// getCacheFilename generates a cache filename based on the URL of the request
// TODO: Use query arguments as well
func getCacheFilename(mangadexURL *url.URL) string {
return strings.ReplaceAll(mangadexURL.Path, "/", "_")
}
// cacheExists checks that the cache for a certain URL exists or not
func cacheExists(mangadexURL *url.URL) bool {
stat, err := os.Stat(getCachePathFor(mangadexURL))
stat, err := os.Stat(getCachePath(mangadexURL))
if os.IsNotExist(err) {
return false
}
return !stat.IsDir()
}
// initCache makes sure that the cache directory exists so reads and writes on cache folders won't fail
func initCache() {
cachePath := getCachePath()
cachePath := getBaseCachePath()
_, err := os.Stat(cachePath)
if os.IsNotExist(err) {
logrus.Infof("Cache directory does not exist, creating. [%s]", cachePath)

14
http.go
View File

@ -11,19 +11,18 @@ import (
"github.com/sirupsen/logrus"
)
const APIBaseURL = "https://api.mangadex.org/v2/"
const apiBaseURL = "https://api.mangadex.org/v2/"
func doRequest(method string, requestURL string) (*MangaDexResponse, error) {
result := MangaDexResponse{}
func doRequest(method string, requestURL string) (*Response, error) {
result := Response{}
parsedURL, errParse := url.Parse(requestURL)
if errParse != nil {
return &result, errParse
}
if cacheEnabled {
initCache()
if cacheExists(parsedURL) {
cacheData, errRead := ioutil.ReadFile(getCachePathFor(parsedURL))
cacheData, errRead := ioutil.ReadFile(getCachePath(parsedURL))
if errRead != nil {
logrus.Fatalf("Error reading cache for URL: %s [%s]: %s", parsedURL.String(), getCacheFilename(parsedURL), errRead)
}
@ -33,9 +32,8 @@ func doRequest(method string, requestURL string) (*MangaDexResponse, error) {
}
logrus.Debugf("Request loaded from cache: %s", parsedURL.String())
return &result, nil
} else {
logrus.Debugf("Cache not found for %s", parsedURL.String())
}
logrus.Debugf("Cache not found for %s", parsedURL.String())
}
logrus.Tracef("Making request %s", parsedURL)
@ -76,7 +74,7 @@ func doRequest(method string, requestURL string) (*MangaDexResponse, error) {
// Write cache
logrus.Infof("Writting cache for %s", parsedURL.String())
logrus.Infof("Writting cache to: %s", getCacheFilename(parsedURL))
errWriteCache := ioutil.WriteFile(getCachePathFor(parsedURL), body, 0644)
errWriteCache := ioutil.WriteFile(getCachePath(parsedURL), body, 0644)
if errWriteCache != nil {
logrus.Warnf("Can't write to cache: %s", errWriteCache)
}

View File

@ -16,13 +16,13 @@ func (manga *Manga) GetChapters(params ChaptersParams) ([]MangaChapterList, []Ma
var mangaGroupsResult []MangaGroup
params.validate()
response, errRequest := doRequest("GET", APIBaseURL+path.Join("manga", strconv.Itoa(manga.ID), "chapters")+"?"+params.asQueryParams().Encode())
response, errRequest := doRequest("GET", apiBaseURL+path.Join("manga", strconv.Itoa(manga.ID), "chapters")+"?"+params.asQueryParams().Encode())
if errRequest != nil {
logrus.Errorf("Request error: %s", errRequest)
return mangaChaptersResult, mangaGroupsResult, errRequest
}
var mangaDexChaptersResponse MangaDexChaptersResponse
var mangaDexChaptersResponse ChaptersResponse
errJSON := json.Unmarshal(response.Data, &mangaDexChaptersResponse)
if errJSON != nil {
@ -39,7 +39,7 @@ func (manga *Manga) GetChapters(params ChaptersParams) ([]MangaChapterList, []Ma
func (manga *Manga) GetChapter(chapter string) (MangaChapterDetail, error) {
var result MangaChapterDetail
response, errRequest := doRequest("GET", APIBaseURL+path.Join("chapter", chapter))
response, errRequest := doRequest("GET", apiBaseURL+path.Join("chapter", chapter))
if errRequest != nil {
logrus.Errorf("Request error: %s", errRequest)
return result, errRequest
@ -57,7 +57,7 @@ func (manga *Manga) GetChapter(chapter string) (MangaChapterDetail, error) {
// GetCovers requests the covers for the provided manga
func (manga *Manga) GetCovers() ([]MangaCover, error) {
var result []MangaCover
response, errRequest := doRequest("GET", APIBaseURL+path.Join("manga", strconv.Itoa(manga.ID), "covers"))
response, errRequest := doRequest("GET", apiBaseURL+path.Join("manga", strconv.Itoa(manga.ID), "covers"))
if errRequest != nil {
logrus.Errorf("Request error: %s", errRequest)
return result, errRequest
@ -73,8 +73,9 @@ func (manga *Manga) GetCovers() ([]MangaCover, error) {
// GetManga retrieves the manga information for the provided ID.
func GetManga(mangaID int) (Manga, error) {
initCache()
result := Manga{}
response, errRequest := doRequest("GET", APIBaseURL+path.Join("manga", strconv.Itoa(mangaID)))
response, errRequest := doRequest("GET", apiBaseURL+path.Join("manga", strconv.Itoa(mangaID)))
if errRequest != nil {
logrus.Errorf("Request error: %s", errRequest)
return result, errRequest

View File

@ -6,7 +6,8 @@ import (
"strconv"
)
type MangaDexResponse struct {
// Response handles the response from MangaDex
type Response struct {
// Same as HTTP status code
Code int `json:"code"`
// `OK` or `error`
@ -17,11 +18,19 @@ type MangaDexResponse struct {
Data json.RawMessage `json:"data"`
}
type MangaDexChaptersResponse struct {
// IsOK Checks if the response is correct
func (response Response) IsOK() bool {
return response.Status == "OK"
}
// ChaptersResponse handles the response of the chapters list which returns
// two kinds of objects in the `json:"data"` key.
type ChaptersResponse struct {
Chapters []MangaChapterList `json:"chapters"`
Groups []MangaGroup `json:"groups"`
}
// MangaRelation relations between mangas
type MangaRelation struct {
ID int `json:"id"`
IsHentai bool `json:"isHentai"`
@ -29,6 +38,8 @@ type MangaRelation struct {
Type int `json:"type"`
}
// MangaPublication stores certain information for the publication of the manga
// Some values are easily guessed, others are not ...
type MangaPublication struct {
// ???
Demographic int8 `json:"demographic"`
@ -37,12 +48,19 @@ type MangaPublication struct {
Language string `json:"language"`
}
// IsComplete returns if the manga has finished publishing
func (publication MangaPublication) IsComplete() bool {
return publication.Status == 2
}
// MangaRating the rating for a particular manga
type MangaRating struct {
Bayesian float32 `json:"bayesian"`
Mean float32 `json:"mean"`
Users int `json:"users"`
}
// MangaLinks contains the relation of the links map with more verbose names
type MangaLinks struct {
AniList string `json:"al"`
AnimePlanet string `json:"ap"`
@ -56,6 +74,7 @@ type MangaLinks struct {
EnglishRaw string `json:"engtl"`
}
// Manga stores the base manga object and details
type Manga struct {
ID int `json:"id"`
AlternativeTitles []string `json:"altTitles"`
@ -78,11 +97,13 @@ type Manga struct {
Views int `json:"views"`
}
// MangaCover stores the cover object
type MangaCover struct {
URL string `json:"url"`
Volume string `json:"volume"`
}
// MangaChapterBase the base attributes for a chapter for both the list and the detail
type MangaChapterBase struct {
ID int `json:"id"`
Hash string `json:"hash"`
@ -99,11 +120,15 @@ type MangaChapterBase struct {
Views int `json:"views"`
}
// MangaChapterList stores the chapter object from the listing, which only uses the
// base details and uses the ID for the groups instead of returning the entire object
type MangaChapterList struct {
MangaChapterBase
Groups []int `json:"groups"`
}
// MangaChapterDetail stores the bases of a chapter plus the required attributes
// to retrieve the page blobs
type MangaChapterDetail struct {
MangaChapterBase
Groups []MangaGroup `json:"groups"`
@ -113,11 +138,13 @@ type MangaChapterDetail struct {
ServerFallback string `json:"serverFallback"`
}
// MangaGroupMember stores the member of a group
type MangaGroupMember struct {
ID int `json:"id"`
Name string `json:"name"`
}
// MangaGroup stores the group behind releases of a particular manga
type MangaGroup struct {
ID int `json:"id"`
Name string `json:"name"`
@ -145,12 +172,17 @@ type MangaGroup struct {
Banner string `json:"banner"`
}
// ChaptersParams the request parameters for the chapters listing
type ChaptersParams struct {
Limit int `json:"limit"`
Page int `json:"p"`
// How many items per page (max 100)
Limit int `json:"limit"`
// Page to retrieve (default 0)
Page int `json:"p"`
// Hide groups blocked by the user (auth not implemented)
BlockGroups bool `json:"blockgroups"`
}
// NewChaptersParams returns a ChapterParams object with sensible defaults
func NewChaptersParams() ChaptersParams {
return ChaptersParams{
Limit: 100,