feat: Updated to use new login/auth procedure on ZiniGo side - uses cookies for the token.
Also added a -playwright=true option for people who dont want to use a pre-installed chrome. Added macos build scripts (and executable)
This commit is contained in:
parent
cf16f9956a
commit
d79c20d8ac
64
Grabazine.go
64
Grabazine.go
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
wkhtml "github.com/SebastiaanKlippert/go-wkhtmltopdf"
|
wkhtml "github.com/SebastiaanKlippert/go-wkhtmltopdf"
|
||||||
"github.com/icza/gox/stringsx"
|
"github.com/icza/gox/stringsx"
|
||||||
|
"github.com/mxschmitt/playwright-go"
|
||||||
"github.com/pdfcpu/pdfcpu/pkg/api"
|
"github.com/pdfcpu/pdfcpu/pkg/api"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
@ -37,6 +38,7 @@ func main() {
|
||||||
chromePtr := flag.String("c", "google-chrome", "Chrome executable")
|
chromePtr := flag.String("c", "google-chrome", "Chrome executable")
|
||||||
zinioHostPtr := flag.String("e", "api-sec.ziniopro.com", "Zinio Host (Excluding port and URI Scheme). Known: `api-sec`, `api-sec-2`")
|
zinioHostPtr := flag.String("e", "api-sec.ziniopro.com", "Zinio Host (Excluding port and URI Scheme). Known: `api-sec`, `api-sec-2`")
|
||||||
exportUsingWKHTML := flag.String("wkhtml", "false", "Use WKHTML instead of Chrome to generate PDF (false by default)")
|
exportUsingWKHTML := flag.String("wkhtml", "false", "Use WKHTML instead of Chrome to generate PDF (false by default)")
|
||||||
|
exportUsingPlaywright := flag.String("playwright", "false", "Use Playwright Chromium instead of local Chrome to generate PDF (false by default)")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
|
@ -68,13 +70,13 @@ func main() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Starting the application...")
|
//fmt.Println("Starting the application...")
|
||||||
initialToken, err := GetInitialToken()
|
//initialToken, err := GetInitialToken()
|
||||||
if err != nil {
|
//if err != nil {
|
||||||
os.Exit(1)
|
// os.Exit(1)
|
||||||
}
|
//}
|
||||||
loginToken := GetLoginToken(initialToken, *usernamePtr, *passwordPtr)
|
loginToken := GetLoginToken(*usernamePtr, *passwordPtr)
|
||||||
issues := GetLibrary(loginToken, initialToken, *zinioHostPtr)
|
issues := GetLibrary(loginToken, *zinioHostPtr)
|
||||||
for i := range issues {
|
for i := range issues {
|
||||||
issueList := issues[i]
|
issueList := issues[i]
|
||||||
//fmt.Println("Found " + strconv.Itoa(len(issues.Data)) + " issues in library.")
|
//fmt.Println("Found " + strconv.Itoa(len(issues.Data)) + " issues in library.")
|
||||||
|
|
@ -84,7 +86,7 @@ func main() {
|
||||||
template, _ := ioutil.ReadFile("template.html")
|
template, _ := ioutil.ReadFile("template.html")
|
||||||
|
|
||||||
if template == nil || len(template) == 0 {
|
if template == nil || len(template) == 0 {
|
||||||
fmt.Println("template.html not found, or empty. using built in template. Consider changing this if your files are cropped.")
|
fmt.Println("template.html not found, or empty. using issue in template. Consider changing this if your files are cropped.")
|
||||||
template = []byte(defaultTemplate)
|
template = []byte(defaultTemplate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,7 +110,7 @@ func main() {
|
||||||
}
|
}
|
||||||
fmt.Println("Downloading issue: " + publicationName + " - " + issueName)
|
fmt.Println("Downloading issue: " + publicationName + " - " + issueName)
|
||||||
|
|
||||||
pages := GetPages(loginToken, issue, initialToken, *zinioHostPtr)
|
pages := GetPages(loginToken, issue, *zinioHostPtr)
|
||||||
|
|
||||||
var filenames []string
|
var filenames []string
|
||||||
|
|
||||||
|
|
@ -141,7 +143,24 @@ func main() {
|
||||||
|
|
||||||
//convert to pdf
|
//convert to pdf
|
||||||
|
|
||||||
if strings.ToLower(*exportUsingWKHTML) == "true" {
|
if strings.ToLower(*exportUsingPlaywright) == "true" {
|
||||||
|
pw, err := playwright.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("could not start playwright: %v", err)
|
||||||
|
}
|
||||||
|
browser, err := pw.Chromium.Launch()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("could not launch browser: %v", err)
|
||||||
|
}
|
||||||
|
context, err := browser.NewContext()
|
||||||
|
|
||||||
|
page, err := context.NewPage()
|
||||||
|
_ = page.SetContent(htmldata, playwright.PageSetContentOptions{WaitUntil: playwright.WaitUntilStateNetworkidle})
|
||||||
|
_, err = page.PDF(playwright.PagePdfOptions{
|
||||||
|
Path: playwright.String(pathString + ".pdf"),
|
||||||
|
})
|
||||||
|
|
||||||
|
} else if strings.ToLower(*exportUsingWKHTML) == "true" {
|
||||||
|
|
||||||
pdfg, err := wkhtml.NewPDFGenerator()
|
pdfg, err := wkhtml.NewPDFGenerator()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -210,7 +229,7 @@ func main() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPages(userToken LoginResponse, issue LibraryData, token string, endpoint string) Response {
|
func GetPages(userToken LoginResponse, issue LibraryData, endpoint string) Response {
|
||||||
|
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
|
|
||||||
|
|
@ -218,8 +237,10 @@ func GetPages(userToken LoginResponse, issue LibraryData, token string, endpoint
|
||||||
req, _ := http.NewRequest("GET", "https://zinio.com/api/newsstand/newsstands/101/issues/"+strconv.Itoa(issue.Id)+"/content/pages?format=svg&application_id=9901&css_content=true&user_id="+userToken.Data.User.UserIDString, nil)
|
req, _ := http.NewRequest("GET", "https://zinio.com/api/newsstand/newsstands/101/issues/"+strconv.Itoa(issue.Id)+"/content/pages?format=svg&application_id=9901&css_content=true&user_id="+userToken.Data.User.UserIDString, nil)
|
||||||
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
req.AddCookie(&http.Cookie{Name: "zwrt", Value: userToken.Data.AccessToken})
|
||||||
|
|
||||||
//req.Header.Add("Authorization", "bearer "+token)
|
//req.Header.Add("Authorization", "bearer "+token)
|
||||||
req.Header.Add("Authorization", token)
|
//req.Header.Add("Authorization", token)
|
||||||
|
|
||||||
resp, _ := client.Do(req)
|
resp, _ := client.Do(req)
|
||||||
data, _ := ioutil.ReadAll(resp.Body)
|
data, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
@ -247,14 +268,14 @@ func GetInitialToken() (token string, err error) {
|
||||||
return string(found[2]), nil
|
return string(found[2]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetLoginToken(initialToken string, username string, password string) LoginResponse {
|
func GetLoginToken(username string, password string) LoginResponse {
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
|
|
||||||
var jsonStr = []byte(`{"username":"` + username + `","password":"` + password + `"}`)
|
var jsonStr = []byte(`{"username":"` + username + `","password":"` + password + `"}`)
|
||||||
req, _ := http.NewRequest("POST", "https://www.zinio.com/api/login?project=99&logger=null", bytes.NewBuffer(jsonStr))
|
req, _ := http.NewRequest("POST", "https://www.zinio.com/api/login?project=99&logger=null", bytes.NewBuffer(jsonStr))
|
||||||
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
req.Header.Add("Authorization", initialToken)
|
//req.Header.Add("Authorization", initialToken)
|
||||||
|
|
||||||
resp, _ := client.Do(req)
|
resp, _ := client.Do(req)
|
||||||
data, _ := ioutil.ReadAll(resp.Body)
|
data, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
@ -263,11 +284,20 @@ func GetLoginToken(initialToken string, username string, password string) LoginR
|
||||||
|
|
||||||
_ = json.Unmarshal([]byte(data), &responseType)
|
_ = json.Unmarshal([]byte(data), &responseType)
|
||||||
|
|
||||||
|
for _, cookie := range resp.Cookies() {
|
||||||
|
if cookie.Name == "zwrt" {
|
||||||
|
responseType.Data.AccessToken = cookie.Value
|
||||||
|
}
|
||||||
|
if cookie.Name == "zwrrt" {
|
||||||
|
responseType.Data.RefreshToken = cookie.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return responseType
|
return responseType
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetLibrary(userToken LoginResponse, initialToken string, endpoint string) []LibraryResponse {
|
func GetLibrary(userToken LoginResponse, endpoint string) []LibraryResponse {
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
|
|
||||||
var itemsToReturn []LibraryResponse
|
var itemsToReturn []LibraryResponse
|
||||||
|
|
@ -278,8 +308,9 @@ func GetLibrary(userToken LoginResponse, initialToken string, endpoint string) [
|
||||||
req, _ := http.NewRequest("GET", "https://zinio.com/api/newsstand/newsstands/101/users/"+userToken.Data.User.UserIDString+"/library_issues?limit="+strconv.Itoa(issuesToFetch)+"&page="+strconv.Itoa(pageToFetch), nil)
|
req, _ := http.NewRequest("GET", "https://zinio.com/api/newsstand/newsstands/101/users/"+userToken.Data.User.UserIDString+"/library_issues?limit="+strconv.Itoa(issuesToFetch)+"&page="+strconv.Itoa(pageToFetch), nil)
|
||||||
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
req.AddCookie(&http.Cookie{Name: "zwrt", Value: userToken.Data.AccessToken})
|
||||||
//req.Header.Add("Authorization", "bearer "+userToken.Data.Token.AccessToken)
|
//req.Header.Add("Authorization", "bearer "+userToken.Data.Token.AccessToken)
|
||||||
req.Header.Add("Authorization", initialToken)
|
//req.Header.Add("Authorization", initialToken)
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
|
|
||||||
|
|
@ -321,6 +352,7 @@ type LoginData struct {
|
||||||
User User `json:"user"`
|
User User `json:"user"`
|
||||||
Token Token `json:"token"`
|
Token Token `json:"token"`
|
||||||
RefreshToken string `json:"refreshToken"`
|
RefreshToken string `json:"refreshToken"`
|
||||||
|
AccessToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
|
|
|
||||||
12
README.md
12
README.md
|
|
@ -12,16 +12,22 @@ ZiniGo can be downloaded for Windows and Linux at https://github.com/TheAxeDude/
|
||||||
|
|
||||||
You can also add these properties to a config file in the working directory, instead of passing them in manually. See the sample at https://github.com/TheAxeDude/ZiniGo/blob/master/config.json
|
You can also add these properties to a config file in the working directory, instead of passing them in manually. See the sample at https://github.com/TheAxeDude/ZiniGo/blob/master/config.json
|
||||||
|
|
||||||
|
You can use `-playwright=true` to use Playwright to run the tests. It'll download a browser in the background.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
Google chrome installed, and accessible via the command `google-chrome`, or at a location passed in via the -c parameter.
|
|
||||||
|
No specific dependencies need to be installed, however you can specify the location of the chrome executable to be used rendering the PDF.
|
||||||
|
|
||||||
|
If using a pre-installed chrome, the command `google-chrome` should work, or a location of the Chrome executable should be passed in via the `-c` parameter.
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
ZiniGo logs into Zinio, and pulls a list of all issues purchased.
|
ZiniGo logs into Zinio, and pulls a list of all issues purchased.
|
||||||
|
|
||||||
Each page is available as an SVG, which is then injected into an HTML page (based on template.html).
|
Each page is available as an SVG, which is then injected into an HTML page (based on template.html).
|
||||||
|
|
||||||
google-chrome is then used to print the page to PDF, and all pages are combined into a single PDF.
|
PlayWright (or google-chrome) is then used to print the page to PDF, and all pages are combined into a single PDF.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
Build for linux & windows on windows using the pwershell script in buildscripts
|
Build for linux & windows on windows using the powershell script in buildscripts
|
||||||
|
Build for linux & windows on macos using the darwin.sh script in buildscripts
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
set GOOS = 'windows'
|
||||||
|
set GOARCH = 'amd64'
|
||||||
|
cd ..
|
||||||
|
go build -o built/Zinigo_Windows_x64.exe Grabazine.go
|
||||||
|
cd buildscripts
|
||||||
|
set GOOS = 'linux'
|
||||||
|
set GOARCH = 'amd64'
|
||||||
|
cd ..
|
||||||
|
go build -o built/Zinigo_Linux_AMD64 Grabazine.go
|
||||||
|
cd buildscripts
|
||||||
|
set GOOS=darwin
|
||||||
|
set GOARCH=amd64
|
||||||
|
cd ..
|
||||||
|
go build -o built/Zinigo_Macos_AMD64 Grabazine.go
|
||||||
|
cd buildscripts
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue