Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Route not found error #44

Open
RupertB-ES opened this issue Mar 26, 2024 · 30 comments
Open

Route not found error #44

RupertB-ES opened this issue Mar 26, 2024 · 30 comments

Comments

@RupertB-ES
Copy link

Got this error after logging in

GotLogin
Fetching Library
Fetching page:1
{"status":false,"error":{"message":"Route not found in ApiRouter","internal_code":"CONTENT_ERROR"}}
Terminating the application...

@dirty1200
Copy link

I get the same error.

@jmskuo
Copy link

jmskuo commented May 28, 2024

I get the error message is {"status":false,"error":{"message":"Route not found in ApiRouter","internal_code":"APPERR13131313"}}

@dirty1200
Copy link

now i also get
{"status":false,"error":{"message":"Route not found in ApiRouter","internal_code":"APPERR13131313"}}

@gabag30
Copy link

gabag30 commented Jul 14, 2024

same here, I was trying to backup my library and run into the issue. Is there any plan to update the tool?

@ms162223
Copy link

I am getting this error as well. I would love to see the project updated. Does anyone know of any alternatives. I have ton of magazines that I have been subscribing to for years and now Zinio wants you to pay monthly for access to old issues that you already paid for.

@muttmutt
Copy link

Same error on both MacOS 14.6.1 and on Ubuntu 22.04.

@TheAxeDude
Copy link
Owner

Looks like Zinio have made a few changes to their backend. I have gotten past the original problem raised, but have encountered a few more - will work on those.

@TheAxeDude
Copy link
Owner

It looks like Zinio no longer has the older SVG-based reader, which this tool was based on. This may be a major roadblock - we will need to look into how their PDF-based reader works. In the long run, this should be better - but will take some time.

@ER-EPR
Copy link

ER-EPR commented Dec 17, 2024

I have successfully fix this problem, it's only because of the get library api changes, the keys now are 'library-issues' 'offset'. And in order to terminate process this change is also needed pageToFetch += issuesToFetch

func GetLibrary(userToken LoginResponse, endpoint string) []LibraryResponse {
	fmt.Println("Fetching Library")
	client := &http.Client{}

	var itemsToReturn []LibraryResponse
	issuesToFetch := 120

	pageToFetch := 0
	for {
		fmt.Println("Fetching page:" + strconv.Itoa(pageToFetch))

		req, _ := http.NewRequest("GET", "https://zinio.com/api/newsstand/newsstands/101/users/"+userToken.Data.User.UserIDString+"/library-issues?limit="+strconv.Itoa(issuesToFetch)+"&offset="+strconv.Itoa(pageToFetch), nil)

		req.Header.Add("Content-Type", "application/json")
		for _, cookie := range userToken.Data.Cookies {
			req.AddCookie(cookie)
		}
		//req.AddCookie(&http.Cookie{Name: "zwrt", Value: userToken.Data.AccessToken})
		//req.Header.Add("Authorization", "bearer "+userToken.Data.Token.AccessToken)
		//req.Header.Add("Authorization", initialToken)

		resp, err := client.Do(req)

		if err != nil {
			fmt.Println("Unable to get Library: " + err.Error())
		}

		data, _ := ioutil.ReadAll(resp.Body)
		fmt.Println(string(data))

		responseType := LibraryResponse{}

		_ = json.Unmarshal(data, &responseType)

		if len(responseType.Data) > 0 {
			itemsToReturn = append(itemsToReturn, responseType)
			pageToFetch += issuesToFetch
		} else {
			break
		}
	}

	return itemsToReturn
}

BTW, the changes I made are based on @motoyugota 's fork.

@SR-G
Copy link

SR-G commented Dec 17, 2024

I can confirm that it's now working ! Good job.

git clone https://github.com/motoyugota/ZiniGo/
cd ZiniGo
git checkout fixgetpages
cd ZiniGo
vi main.go   # then just replace the whole content of the "GetLibrary" method

go build .

mkdir "issue/"  # otherwise weird permissions ... but still, generated files have now weird permissions
cp ../built/template.html .
./ZiniGo

But in the generated .PDF, i have a weird "PDF note" (small note in top left corner) everywhere (with the content "page=Cover", etc.). Was not happening before / don't know from where this is coming. The template.html ?

@SR-G
Copy link

SR-G commented Dec 17, 2024

Ok so i still don't know from where these "notes" are coming (it seems to be "sticky notes"), but to remove them, i just had to add (line 186) :

			_ = api.MergeCreateFile(filenames, completeName, nil)
			err2 := api.RemoveAnnotationsFile(completeName, "", nil, nil, nil, nil, false)
			if err2 != nil {
				fmt.Println(err2)
			}

@SR-G
Copy link

SR-G commented Dec 17, 2024

(sorry, several edits, i should stop writing this comment alongside my tests ...)

First, i encountered again some Removing extra pages failed with pdfcpu: please provide the correct password errors.

This is solved like this (removal of the "N retry with a delay" in order to try one time without password, one time with the conf object containing the password, as it seems that some .PDF are password protected, and some are not !).

err = api.RemovePagesFile(filenames[i], "", []string{"2-"}, nil)
if err != nil {
	fmt.Printf("Removing extra pages from ["+filenames[i]+"] failed with %s\n.", err)
	err = api.RemovePagesFile(filenames[i], "", []string{"2-"}, conf)
	if err != nil {
		fmt.Printf("Removing extra pages from ["+filenames[i]+"] still failed with %s\n.", err)
	}
}

Then i encountered some errors (now displayed) about unsupported PDF features

.Removing extra pages from [...] still failed with dict=markupAnnot entry=RC: unsupported in version 1.4
This file could be PDF/A compliant but pdfcpu only supports versions <= PDF V1.7

This is related to : pdfcpu/pdfcpu#654
Upgrading the component in go.mod seems to work :

github.com/pdfcpu/pdfcpu v0.9.1

with two code changes :

  • one extra boolean here : _ = api.MergeCreateFile(filenames, completeName, false, nil)
  • and change of package (pdfcpu > model) here conf := model.NewAESConfiguration(passwordToUse, passwordToUse, 256)

At this point on my side, it seems WAY better now.

image

@shmimel
Copy link

shmimel commented Dec 18, 2024

@SR-G, nothing more exciting than seeing fresh comments on a repo! Nice job :) Last month I wrote an AHK script that prints each individual page to PDF and combines into one big one because I didn't have the skills to troubleshoot...

@ER-EPR
Copy link

ER-EPR commented Dec 18, 2024

@SR-G I was hoping I can fix those problem after I learn some more golang. I've never coded in go. I don't know why I got a .\main.go:142:12: undefined: model following your instructions. I modified go.mod and use go mode tidy to update. But it seems you also change some names of the variant?

@ER-EPR
Copy link

ER-EPR commented Dec 18, 2024

After a go mode tidy and go get -u ./... run in the same directory with go.mod and go.sum. The error was gone and it works perfectly. Thanks @SR-G
for any Golang beginners like me, your main function needs to be like this:

func main() {

	usernamePtr := flag.String("u", "", "Zinio Username")
	passwordPtr := flag.String("p", "", "Zinio Password")
	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`")
	//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)")
	deviceFingerprintPtr := flag.String("fingerprint", "abcd123", "This devices fingerprint - presented to Zinio API")

	flag.Parse()

	mydir, err := os.Getwd()
	if err != nil {
		fmt.Println(err)
	}

	if fileExists(mydir + "/config.json") {
		fmt.Println("Config file loaded")
		byteValue, _ := ioutil.ReadFile("config.json")
		username := gjson.GetBytes(byteValue, "username")
		if username.Exists() {
			*usernamePtr = username.String()
			fmt.Println("Username taken from config file")
		}

		password := gjson.GetBytes(byteValue, "password")
		if password.Exists() {
			*passwordPtr = password.String()
			fmt.Println("password taken from config file")
		}

		chrome := gjson.GetBytes(byteValue, "chromepath")
		if chrome.Exists() {
			*chromePtr = chrome.String()
			fmt.Println("chromepath taken from config file")
		}

		fingerprint := gjson.GetBytes(byteValue, "fingerprint")
		if fingerprint.Exists() {
			*deviceFingerprintPtr = fingerprint.String()
			fmt.Println("Fingerprint taken from config file")
		} else {
			fmt.Println("No fingerprint found in text file, generating and writing")
			newJson, _ := sjson.Set(string(byteValue), "fingerprint", randSeq(15))

			err := ioutil.WriteFile("config.json", []byte(newJson), 0644)
			if err != nil {
				log.Fatalf("unable to write file: %v", err)
			}
		}

	}

	//fmt.Println("Starting the application...")
	//initialToken, err := GetInitialToken()
	//if err != nil {
	//	os.Exit(1)
	//}
	loginToken := GetLoginToken(*usernamePtr, *passwordPtr, *deviceFingerprintPtr)
	issues := GetLibrary(loginToken, *zinioHostPtr)
	for i := range issues {
		issueList := issues[i]

		//fmt.Println("Found " + strconv.Itoa(len(issues.Data)) + " issues in library.")

		fmt.Println("Loading HTML template")
		defaultTemplate := GetDefaultTemplate()
		template, _ := ioutil.ReadFile("template.html")

		if template == nil || len(template) == 0 {
			fmt.Println("template.html not found, or empty. using issue in template. Consider changing this if your files are cropped.")
			template = []byte(defaultTemplate)
		}

		fmt.Println("Resolved working directory to: " + mydir)
		//fmt.Println("Grabbing list of pages...")
		issueDirectory := filepath.Join(mydir, "issue")
		if _, err := os.Stat(issueDirectory); os.IsNotExist(err) {
			os.Mkdir(issueDirectory, 0600)
		}

		for _, issue := range issueList.Data {

			issueDetails := GetIssueDetails(loginToken, issue.Id)
			isLegacy := issueDetails.Data.Issue.Publication.LegacyContent == 1
			passwordToUse := issueDetails.Data.Issue.Hash
			if isLegacy {
				passwordToUse = issueDetails.Data.Issue.LegacyHash
			}
			fmt.Println(issue)
			issuePath := filepath.Join(issueDirectory, strconv.Itoa(issue.Id))

			publicationName := RemoveBadCharacters(issue.Publication.Name)
			issueName := RemoveBadCharacters(issue.Name)

			completeName := filepath.Join(issueDirectory, publicationName+" - "+issueName+".pdf")
			fmt.Println("Checking if issue exists: " + completeName)
			if fileExists(completeName) {
				fmt.Println("Issue already found: " + completeName)
				continue
			}
			fmt.Println("Downloading issue: " + publicationName + " - " + issueName)

			pages := GetPages(loginToken, issue, *zinioHostPtr)

			var filenames []string
			conf := model.NewAESConfiguration(passwordToUse, passwordToUse, 256)
			for i := 0; i < len(pages.Data.Pages); i++ {
				if len(pages.Data.Pages[i].Src) == 0 {

					fmt.Println("No Download URL for page ", i)
					continue
				}
				fmt.Println("Source ", pages.Data.Pages[i].Src)
				fmt.Println("ID: ", pages.Data.Pages[i].Index)

				pathString := issuePath + "_" + pages.Data.Pages[i].Index

				resp, err := http.Get(pages.Data.Pages[i].Src)
				// handle the error if there is one
				if err != nil {
					panic(err)
				}
				// do this now so it won't be forgotten
				defer resp.Body.Close()
				// reads html as a slice of bytes
				html, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					panic(err)
				}
				ioutil.WriteFile(pathString+".pdf", html, 0644)
				api.DecryptFile(pathString+".pdf", "", conf)

				filenames = append(filenames, pathString+".pdf")
			}

			for i := range filenames {
				//remove last page

				//err = retry(5, 2*time.Second, func() (err error) {
				err = api.RemovePagesFile(filenames[i], "", []string{"2-"}, nil)
				if err != nil {
					fmt.Printf("Removing extra pages from ["+filenames[i]+"] failed with %s\n.", err)
					err = api.RemovePagesFile(filenames[i], "", []string{"2-"}, conf)
					if err != nil {
						fmt.Printf("Removing extra pages from ["+filenames[i]+"] still failed with %s\n.", err)
					}
				}

				//	return
				//})
			}

			_ = api.MergeCreateFile(filenames, completeName, false, nil)
			err2 := api.RemoveAnnotationsFile(completeName, "", nil, nil, nil, nil, false)
			if err2 != nil {
				fmt.Println(err2)
			}
			for _, fileName := range filenames {
				_ = os.Remove(fileName)
			}
		}

	}

	fmt.Println("Terminating the application...")

}

@ER-EPR
Copy link

ER-EPR commented Dec 18, 2024

But now I encounter this problem pdfcpu/pdfcpu#901 some of the encrypted file have incorrect date thich crash pdfcpu.

@SR-G
Copy link

SR-G commented Dec 18, 2024

Sadly the pdfcpu (which i don't know well) seems to not be very flexible :

  • they removed the "ValidationNone" feature (as visible in other issues of the project)
  • as a consequence, any error in the PDF prevents it to be processed by this library
  • it seems that when there are "weird date pattern", they are manually adding "local corrections" inside the library ... but it's an endless job and IMHO not the proper approach

So there are several options :

  1. Use pdfcpu to remove "Keywords" (= to blank the dates) : pretty sure this will fail, as their "validation" step will still be applied in the api.RemoveKeywordsFile() operation
  2. Have pdfcpu locally correct their date parsing regarding the encountered error : again, endless job, new issues may be encountered here and there again and again over time (this is what you asked in the #901 issue) - this should of course work (once done), but again, the same issue may appear tomorrow with another weird date pattern in the Zinio generated content
  3. Find another golang PDF library (at least to "clean" the keywords / metadata in the PDF before pdfcpu is triggered)
  4. At worst, clean up the metadata in another way (for example, even if it's an horrible solution ..., by triggering the remote command pdftk on the generated files, and use it to remove the metadata (it's an ugly solution as it would fork another CLI process for each page that needs to be cleaned ...))

(i'm speaking about "cleaning up the metadata" in order to "prepare" the temporary .PDF and have them ready to be processed by pdfcpu as it is nowadays in the ZiniGo code)

@ER-EPR
Copy link

ER-EPR commented Dec 18, 2024

I tried https://github.com/sfomuseum/go-pdfbox.git and https://pkg.go.dev/github.com/KarmaPenny/pdfparser
But they all get a nil pointer dereference error

.panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x41a483]

goroutine 1 [running]:
github.com/KarmaPenny/pdfparser/pdf.Debug({0x668323?, 0xc0000e20b8?}, {0x0?, 0x0?, 0x65?})
        C:/Users/xu_co/go/pkg/mod/github.com/!karma!penny/pdfparser@v1.1.0/pdf/logger.go:11 +0x23
github.com/KarmaPenny/pdfparser/pdf.Parse({0x66cfe3?, 0xc000062030?}, {0x67bf57, 0x28}, {0x6649e9, 0x6})
        C:/Users/xu_co/go/pkg/mod/github.com/!karma!penny/pdfparser@v1.1.0/pdf/pdf.go:27 +0x125
main.main.func1()
        C:/Users/xu_co/Downloads/ZiniGo/ZiniGo/main.go:181 +0x176
main.retry(0x2, 0x77359400, 0xc000115f18)
        C:/Users/xu_co/Downloads/ZiniGo/ZiniGo/main.go:404 +0x89
main.main()
        C:/Users/xu_co/Downloads/ZiniGo/ZiniGo/main.go:177 +0x1877

the code is something like this

ctx := context.Background()
     p, _ := pdfbox.New(ctx, "pdfbox://")
     p.Execute(ctx, "Decrypt", "-password", passwordToUse, filenames[i], filenames[i]) 

according to https://pdfbox.apache.org/2.0/commandline.html
or
pdf.Parse(filenames[i], passwordToUse, issueDirectory)
but all result in the error above.

@TheAxeDude
Copy link
Owner

@ER-EPR in my last experiments, it seemed that Zinio had stopped using the "Legacy" flag to mark files, and set the PDF. Unfortunately, my library isnt very big so none of my issues actually used this.

It almost seemed at some point like every other page was using a different password.

I have got a version using c# (Im a lot more familiar with c# than golang - this was just an experimental project for me) which I can try to get cleaned up and uploaded here.

Im not sure if makes sense to archive this repo and move to a new one, anyone have thoughts?

@RupertB-ES
Copy link
Author

I think it would be best to "cap" the go archive with a build with the main extract fix in it and create a new C# archive

@SR-G
Copy link

SR-G commented Dec 18, 2024

But i don't understand @TheAxeDude your last comment - with the previous comments from yesterday, a lot of things are still working here :

  • API issues solved : issues are found in library, pages are found again in issues
  • .SVG / .PDF download is working fine
  • no more issue with password (some files are NOT password protected, some files are decrypted with the password of the user)
  • extra sticky notes are easily removable
  • extra issues are solved by upgrading the pdfcpu

What remains seems only to be (for SOME of the pages downloaded) the weird date, at this time unparseable by the PDFCPU library.
But, again, it's working fine now (since yesterday) for most files.

@dirty1200
Copy link

im no coder at all!
how go i make a go file?
i have go installed and visual studio code installed.
im on OSX

thanks!

@SR-G
Copy link

SR-G commented Dec 18, 2024

@ER-EPR So, i made a few extra tests (after having been able to be in a situation with the same wrong date than you), and i think i've understood a few things.

First, many issues were coming from the failure of executions at 'decrypt time'

The biggest problem has been since a long time the fact that ... all errors at decrypt time are hidden :

os.WriteFile(pathString+".pdf", html, 0644)
api.DecryptFile(pathString+".pdf", "", conf)

So in case of failures here, everything else was broken (and no valid PDF in the end) : and this is why sometimes some temporary pages were found on disk and were asking for a password : because decrypt had silently failed !

Of course proper pattern is just :

os.WriteFile(pathString+".pdf", html, 0644)
err = api.DecryptFile(pathString+".pdf", "", conf)
if err != nil {
	fmt.Println("Can't decrypt ["+pathString+".pdf] : ", err)
}

And then we can see the errors, like (what you were encountering) the errors with the weird dates.

How to solve the errors about weird dates (still with PDFCPU)

As said before and after having checked the code, the pdfcpu is really not flexible at all (= it's very difficult to change it's behavior, or to use internal deep parts, like altering the validation).

However, in local, and before they would be able to handle the situation with these specific dates (or, better, if they would introduce a "NoDateValidation" mode, etc.), you can do the following :

  • in main folder, type go mod vendor : this will "copy" all the github dependencies inside your project, and then this is what will be used (and not anymore the OS global GO cache). By doing like, it's easy to "patch" the remote library
  • open the vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types/date.go file in your editor and add this "if" in the prevalidateDate method (line 57, i would say) :
(...)
	// Remove trailing 0x00
	s = strings.TrimRight(s, "\x00")

	if strings.Contains(s, "-001-1-1-1-1-1-00") {
		s = "D:20000101100000Z" // YYYYMMDDHHmmSSZ
	}

	if relaxed {
(...)

The principle is obvious : this method is executed BEFORE the dates are parsed, and there we are "sanitizing" it, by removing the weird string and putting a valid date (i think a valid date is still needed, per the followup lines). And the good thing is that it solves all situations (Decrypt, Merge pages, RemovePages, ... : they are all in need of a 100% valid PDF and were all failing before).

Like this, at least this error should be easily corrected.

Of course it's more a temporary hack than anything else, and a proper fix should be applied in the pdfcpu library (per the #910 issue in their repo).

However I would be curious to see if this is working on your side ;)

@SR-G
Copy link

SR-G commented Dec 18, 2024

im no coder at all! how go i make a go file? i have go installed and visual studio code installed. im on OSX

thanks!

go build -o zinigo ZiniGo/main.go

@ER-EPR
Copy link

ER-EPR commented Dec 19, 2024

@SR-G It works quite well! I change it a little bit, by remove all dashes from the string and replace them with '0'. And now no error at all. Thanks very much
in pkg/pdfcpu/types/data.go line 57

if relaxed {
		// Accept missing "D:" prefix.
		// "YYYY" is mandatory
		s = strings.TrimPrefix(s, "D:")
		s = strings.TrimSpace(s)
		s = strings.ReplaceAll(s, ".", "")
		s = strings.ReplaceAll(s, "-", "0")
		s = strings.ReplaceAll(s, "\\", "")
		return s, len(s) >= 4
	}

I can see the downloaded pages was OK only encrypted before this correction, it is the api.decrypt process fail and the following remove page and merge will too. I also use Stirling PDF docker container to decrypt and merge those pages before, by using it's pipeline function, and success. But nothing is comparable to this perfect fix, thanks again.

@ER-EPR
Copy link

ER-EPR commented Dec 19, 2024

@ER-EPR in my last experiments, it seemed that Zinio had stopped using the "Legacy" flag to mark files, and set the PDF. Unfortunately, my library isnt very big so none of my issues actually used this.

It almost seemed at some point like every other page was using a different password.

I have got a version using c# (Im a lot more familiar with c# than golang - this was just an experimental project for me) which I can try to get cleaned up and uploaded here.

Im not sure if makes sense to archive this repo and move to a new one, anyone have thoughts?

@TheAxeDude I think you can approve the pull request #40, merge it and you can integrate the code I provided above in getLibrary, and @SR-G's enhancements, then you would find it working flawlessly.

@TheAxeDude
Copy link
Owner

I will try to spend some time on that this weekend! Thank you :)

@dirty1200
Copy link

im too stupid to get this to work on osx....
so a new file update/download would be great :)

@shmimel
Copy link

shmimel commented Jan 2, 2025

Even after building, I'm still getting the "Route not found" error. Am I missing something here? I checked with the latest pull request and I have the most recent main.go file in the repo so I am a little confused.

@SR-G
Copy link

SR-G commented Jan 2, 2025

Not sure what you did (i don't understand your "i have the most recent main.go file in the repo" part - especially, you do NOT want the most recent one from this repo, but the one from the pull request + all the adjustements discussed in previous comments).

I tested 5 min ago and it's still working on my side.

Also i pushed my changes here (incl. the "vendor" stuff) (but there are still some uneeded tests inside the code), you should be able to grab it from there and build the binary (or use the one commited at the root, for linux)
https://github.com/SR-G/ZiniGo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants