J-Novel Club
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Users

    Developer PSA: labs.j-novel.club is your new friend!

    Suggestions & Feedback
    25
    81
    11406
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • chocolatkey
      chocolatkey Staff last edited by chocolatkey

      Sometime next year, api.j-novel.club as you know it will cease to function. Some endpoints, most notably anything involving stripe (purchases, subscriptions) and part reading will be shut down earlier than others (ebook downloads already have been). There's no better time than now to start moving your sites, scripts and whatnot to our new API, available at https://labs.j-novel.club (if you hang out in dev tools you may have noticed our new site has started using it more and more).
      Some notable points:

      • There are no official docs or protobuf downloads yet available. We may or may not provide docs in the future.
      • There are no guarantees that there will be no breaking changes, despite the "v1" in the URL. There probably won't be any surprises though.
      • Endpoints return protobuf-encoded responses by default. If you want to get JSON, add format=json to the query. If you want a text dump format, format=text.
      • The new API is less flexible than the old API. This is by design. If there's really really something you feel should be possible, you can request it in this thread, do note that this API is not finished yet though.
      • If you're POSTing data, be sure to include the correct content-type. Protobufs or JSON works
      • Auth either via access_token cookie, access_token query param, or Authorization header Bearer {access token}
      • In case you hadn't noticed, yes I am looking for some dogfooding

      An incomplete list of endpoints:

      https://labs.j-novel.club/feed/user/{user ID} (self-documenting)
      https://labs.j-novel.club/feed/series/{series ID} (self-documenting)
      
      GET https://labs.j-novel.club/embed/{part ID}
      GET https://labs.j-novel.club/embed/{part ID}/info.json
      GET https://labs.j-novel.club/embed/{part ID}/lastpage.html
      GET https://labs.j-novel.club/embed/{part ID}/data.xhtml
      
      GET https://labs.j-novel.club/app/v1/releases
      GET/POST https://labs.j-novel.club/app/v1/series
      GET https://labs.j-novel.club/app/v1/series/{ID or slug}
      GET https://labs.j-novel.club/app/v1/series/{ID or slug}/volumes
      GET https://labs.j-novel.club/app/v1/series/{ID or slug}/aggregate
      GET https://labs.j-novel.club/app/v1/volumes/{ID or slug}
      GET https://labs.j-novel.club/app/v1/volumes/{ID or slug}/serie
      GET https://labs.j-novel.club/app/v1/volumes/{ID or slug}/parts
      GET https://labs.j-novel.club/app/v1/volumes/{ID or slug}/skus
      GET https://labs.j-novel.club/app/v1/volumes/{ID or slug}/price
      GET https://labs.j-novel.club/app/v1/parts/{ID or slug}
      GET https://labs.j-novel.club/app/v1/parts/{ID or slug}/toc
      GET https://labs.j-novel.club/app/v1/parts/{ID or slug}/volume
      GET https://labs.j-novel.club/app/v1/parts/{ID or slug}/serie
      GET https://labs.j-novel.club/app/v1/parts/{ID or slug}/data
      GET https://labs.j-novel.club/app/v1/events
      
      GET/PUT https://labs.j-novel.club/app/v1/me
      GET/POST https://labs.j-novel.club/app/v1/me/subscription
      POST https://labs.j-novel.club/app/v1/me/subscription/sync
      POST/DELETE https://labs.j-novel.club/app/v1/me/subscription/cancel
      POST https://labs.j-novel.club/app/v1/me/subscription/estimate
      GET/DELETE/PUT https://labs.j-novel.club/app/v1/me/method
      GET https://labs.j-novel.club/app/v1/me/method/setup
      POST https://labs.j-novel.club/app/v1/me/otp4app/{otp}
      POST https://labs.j-novel.club/app/v1/me/coins/purchase
      POST https://labs.j-novel.club/app/v1/me/coins/redeem/{ID or slug}
      GET https://labs.j-novel.club/app/v1/me/coins/options
      GET https://labs.j-novel.club/app/v1/me/history
      GET https://labs.j-novel.club/app/v1/me/library
      GET https://labs.j-novel.club/app/v1/me/library/{book copy ID}
      GET https://labs.j-novel.club/app/v1/me/library/{book copy ID}/epub
      GET https://labs.j-novel.club/app/v1/me/library/volume/{volume ID}
      PUT https://labs.j-novel.club/app/v1/me/completion
      HEAD/DELETE/PUT https://labs.j-novel.club/app/v1/me/follow/{serie ID}
      
      POST https://labs.j-novel.club/app/v1/auth/login
      POST https://labs.j-novel.club/app/v1/auth/logout
      GET https://labs.j-novel.club/app/v1/auth/otp4app/generate
      GET/DELETE https://labs.j-novel.club/app/v1/auth/otp4app/check/{otp}/{proof}
      POST https://labs.j-novel.club/app/v1/auth/otp4app/generate
      POST https://labs.j-novel.club/app/v1/auth/reset
      POST https://labs.j-novel.club/app/v1/auth/register
      
      POST https://labs.j-novel.club/app/v1/newsletter
      GET https://labs.j-novel.club/app/v1/plans
      
      Shiny M Ran 3 Replies Last reply Reply Quote 7
      • Shiny
        Shiny Premium Member @chocolatkey last edited by Shiny

        This post is deleted!
        Shiny 1 Reply Last reply Reply Quote 0
        • Shiny
          Shiny Premium Member @Shiny last edited by

          This post is deleted!
          1 Reply Last reply Reply Quote 0
          • Crimson Wise
            Crimson Wise Premium Member last edited by

            Thanks for the notice! I'll be giving it a try with my PWA.

            Any chance of opening CORS to everyone? The old API returns the following headers on the responses:

            access-control-allow-credentials: true
            access-control-allow-origin: <my-request-origin>
            

            Whereas the new one doesn't configure anything related to CORS, so requests get rejected by the browser if using JavaScript.

            Quof got a break.
            WHAT'S THE STORY WITH THAT FREAKING BLACK DRAGON?!

            chocolatkey 1 Reply Last reply Reply Quote 0
            • chocolatkey
              chocolatkey Staff @Crimson Wise last edited by

              @crimson-wise Could you please instead let me know what origins you'd like to use the API from? That goes for anyone else here

              Crimson Wise 1 Reply Last reply Reply Quote 0
              • Crimson Wise
                Crimson Wise Premium Member @chocolatkey last edited by

                @chocolatkey Thanks. In that case "jnc-reader.wscr.dev" and "jnc-reader-dev.wscr.dev" should do for me.

                Quof got a break.
                WHAT'S THE STORY WITH THAT FREAKING BLACK DRAGON?!

                chocolatkey 1 Reply Last reply Reply Quote 0
                • chocolatkey
                  chocolatkey Staff @Crimson Wise last edited by

                  @crimson-wise done

                  1 Reply Last reply Reply Quote 1
                  • redmasq
                    redmasq Premium Member last edited by

                    Just curious, when sign-in is implemented, are you planning it to be credentials only, or will we need to get an api key, client cert, or such?

                    chocolatkey 1 Reply Last reply Reply Quote 0
                    • chocolatkey
                      chocolatkey Staff @redmasq last edited by

                      @redmasq There's really no point in restricting it in that manner, which can simply be circumvented by using a non-browser client or setting up a proxy to the API. More work for me, more work for you, zero sum game

                      redmasq 1 Reply Last reply Reply Quote 1
                      • redmasq
                        redmasq Premium Member @chocolatkey last edited by

                        @chocolatkey I only ask since such extra measures have been en vogue as of late. I was thinking of doing a plugin for my copy of Calibre to get updates to ebooks and such.

                        1 Reply Last reply Reply Quote 0
                        • chocolatkey
                          chocolatkey Staff last edited by chocolatkey

                          Added https://labs.j-novel.club/app/v1/auth/login and https://labs.j-novel.club/app/v1/auth/logout

                          Login payload (in JSON) is {"login":"<email or username>","password":"<password>"}. Optionally, slim: true can be added if all you need is a token, and don't need cookies.
                          400 is your fault, 404 means user not found, 401 means bad pass, 429 means too many tries, else assume a temporary outage or bug

                          Logout is just POST with valid auth to delete session associated with token and expire the cookies.

                          I 1 Reply Last reply Reply Quote 3
                          • I
                            Icerius Premium Member @chocolatkey last edited by

                            @chocolatkey I would recommend returning 401 for both user not found and invalid password.

                            It is considered best practice to return the same result during authentication irrespective of if the error is invalid user or invalid pass

                            See chapter "Authentication and Error messages" in https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html for more info

                            chocolatkey 1 Reply Last reply Reply Quote 0
                            • chocolatkey
                              chocolatkey Staff @Icerius last edited by

                              @icerius that's a fair point, it's changed now. There are still technically ways to enumerate users, thought I won't mention them.

                              redmasq 1 Reply Last reply Reply Quote 0
                              • redmasq
                                redmasq Premium Member @chocolatkey last edited by

                                @chocolatkey Thanks for the hard work.

                                Concerning the username scraping, with that vector plugged up, the easiest way, if reading above correctly, would be once logged in, using rainbow tables, but a moot point since I'm fairly certain someone with a valid username can harvest from these forums anyways, in theory. Logging mixed with governor limits per login identity and per IP/subnet should mitigate much of that style. At least for stuff that I have maintained, an expiring minutely and a rolling daily counter set usually suffices. That selection allowed me to manage the minutely collection in-memory and queue up daily to allow atomic transactions for log and aggregate counts.

                                Regardless, hoping to setup keeping my local copies auto synced, so might code up a cron job this weekend. I may be willing to share a wrapper of whatever language I use if there is interest. Node.js (JavaScript), Python, or Powershell will be my most likely one of my choices, provided I don't get assigned honey-dos (not that this sort of thing is much more than http request and deserialization, but wouldn't be the first time).

                                chocolatkey 1 Reply Last reply Reply Quote 0
                                • chocolatkey
                                  chocolatkey Staff @redmasq last edited by

                                  This post is deleted!
                                  1 Reply Last reply Reply Quote 0
                                  • Crimson Wise
                                    Crimson Wise Premium Member last edited by

                                    I am looking for some dogfooding

                                    For reference, which kind of feedback are you looking for?

                                    Quof got a break.
                                    WHAT'S THE STORY WITH THAT FREAKING BLACK DRAGON?!

                                    1 Reply Last reply Reply Quote 0
                                    • J
                                      jhkghl678690iop Member last edited by jhkghl678690iop

                                      One thing is in order to get all the parts of the serie, it is possible to call:

                                      GET https://labs.j-novel.club/app/v1/parts/{ID or slug}/toc
                                      

                                      But the ID of a part of the series needs to be obtained first. Wouldn't it make more sense to have instead something like?

                                      GET https://labs.j-novel.club/app/v1/series/{ID or slug}/parts
                                      

                                      (ie using the series ID)

                                      chocolatkey 1 Reply Last reply Reply Quote 1
                                      • chocolatkey
                                        chocolatkey Staff @jhkghl678690iop last edited by

                                        @jhkghl678690iop I can add that. It was originally constructed this way for the app's sake

                                        1 Reply Last reply Reply Quote 0
                                        • M
                                          Malloc Premium Member last edited by

                                          I am having a hard time getting part data for a part that requires me to be logged in to download. On the old api, I would set up a header on the html GET request with a header called "Authorization" with a value of the sessionID I got from the login.

                                          However, when I use the new API: "https://labs.j-novel.club/embed/{part ID}/data.xml" it always returns forbidden when I pass the session id in the Authorization header. I have the both the session id (from the old login API) and access cookie I got from the "set-cookie" header on the login response. However I don't know what header to put it in with the new api.

                                          I have tried to figure out what headers to use however when downloading a part using your websites reader the headers appear to be hidden on the HTML request when using Chrome's developer tools but it appears the headers on the data.xml are hidden because it is embeded into a blob:https://labs.j-novel.club/XXXXX call

                                          Crimson Wise 1 Reply Last reply Reply Quote 0
                                          • Crimson Wise
                                            Crimson Wise Premium Member @Malloc last edited by Crimson Wise

                                            @malloc

                                            I'm doing the following (replace XXX, YYY and ZZZ as required) and it works:

                                            $ curl -X POST 'https://api.j-novel.club/api/users/login' -H 'Content-Type: application/json' -d '{"email":"XXX", "password":"YYY"}' -s
                                              {"id":"ZZZ","ttl":1209600,...}
                                            
                                            $ curl 'https://labs.j-novel.club/embed/61d760a893e1a3e2123d0fb5/data.xhtml' -H 'Authorization: Bearer ZZZ' -s | head -n 6
                                              <?xml version="1.0" encoding="UTF-8"?>
                                              <!DOCTYPE html>
                                              <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xmlns:xml="http://www.w3.org/XML/1998/namespace" lang="en" xml:lang="en">
                                              <head>
                                                <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
                                                <title>Guide to the Perfect Otaku Girlfriend: Roomies and Romance Volume 5 Part 2</title>
                                            

                                            You can also use instead the token from the new login endpoint and also works.

                                            Quof got a break.
                                            WHAT'S THE STORY WITH THAT FREAKING BLACK DRAGON?!

                                            M chocolatkey 2 Replies Last reply Reply Quote 0
                                            • 1
                                            • 2
                                            • 3
                                            • 4
                                            • 5
                                            • 1 / 5
                                            • First post
                                              Last post