MangaDexSharp - C# nuget package for api.mangadex.org

Group Leader
Joined
Feb 1, 2023
Messages
20
I wrote a partial implementation of the mangadex API for my reverse image search application, however, it was heavily integrated in the rest of the application, so I decided to split it out and re-work it, kinda.

So here it is:
A C# .net standard 2.1 library for accessing the MangaDex api.
Github: https://github.com/calico-crusade/mangadex-sharp
Nuget: https://www.nuget.org/packages/MangaDexSharp

Currently, it only supports the /chapter, /manga, /author, /cover, and /at-home endpoints, but I'll be adding more when I have time.
Supports most endpoints, excluding: report, scanlation group, settings, upload, user. I'm working on adding more.

Here is a basic usage example:

C#:
var api = MangaDex.Create();

//Fetching a manga by manga ID:
var manga = await api.Manga.Get("fc0a7b86-992e-4126-b30f-ca04811979bf");

//Searching for a manga via it's title:
var results = await api.Manga.List(new MangaFilter
{
    Title = "The Unrivaled Mememori-kun"
});

//Get all of the chapters from a manga by manga ID:
var chapters = await api.Manga.Feed("fc0a7b86-992e-4126-b30f-ca04811979bf");

//Fetch a chapter by chapter ID:
var chapter = await api.Chapter.Get("2c98fbe9-a63f-47c2-9862-ecc9199610a2");

//Get all of the pages of a specific chapter by chapter ID:
var pages = await api.Pages.Pages("2c98fbe9-a63f-47c2-9862-ecc9199610a2");

By default, it supports Dependency Injection for use with asp.net core, there is more information on this in the readme in the nuget package and the github page.

Let me know if you have any questions or suggestions.

Edit: Added more endpoints
Edit 2: Adding even more endpoints
Edit 3: Adding EVEN more endpoints
Edit 4: Adding ALL the endpoints. They are all belong to me.
Edit 5: Fixing documentation of Pages endpoint.
 
Last edited:
Group Leader
Joined
Feb 1, 2023
Messages
20
Group Leader
Joined
Feb 1, 2023
Messages
20
Shouldn't this be
C#:
var pages = await api.Pages.Pages("<id>");

I tried Get but that just gave me an error.
Same problem on the GH ReadMe
You're correct. It was originally api.Pages.Get but I changed it as I introduced more of the endpoints. All of the api endpoint groups that only have 1 or 2 routes were grouped into the same "Misc" service within the API as it didn't make sense to have all of them have their own service.
mdsharp-api.png


Do you think it would be better for it to be
C#:
api.Pages.Get("<id>"); //This way is more phonetically correct, but would introduce a breaking change in the API
or
C#:
api.Pages.Pages("<id>"); //This is the current way of doing things and makes sense in the context of the "misc" service.

I can do either depending on preference. I don't really mind either way; regardless, I'll update the docs and the original post with the current method.
 
Group Leader
Joined
Jan 7, 2023
Messages
32
You're correct. It was originally api.Pages.Get but I changed it as I introduced more of the endpoints. All of the api endpoint groups that only have 1 or 2 routes were grouped into the same "Misc" service within the API as it didn't make sense to have all of them have their own service.
mdsharp-api.png


Do you think it would be better for it to be
C#:
api.Pages.Get("<id>"); //This way is more phonetically correct, but would introduce a breaking change in the API
or
C#:
api.Pages.Pages("<id>"); //This is the current way of doing things and makes sense in the context of the "misc" service.

I can do either depending on preference. I don't really mind either way; regardless, I'll update the docs and the original post with the current method.
If it's correctly documented how it is right now should be fine
 
Group Leader
Joined
Feb 1, 2023
Messages
20
I released a decently massive update to the MD#, most of it is just documentation comments to make development easier, but there are a few useful tools in there as well.
image.png


Specifically, the new pagination utility will take most of the guess work out of getting all results from MD's paginated endpoints. These can be setup manually for any endpoint, but I've added some default ones for things like the /manga and /manga/{id}/feed endpoints.

C#:
var api = MangaDex.Create();

//This will fetch every chapter available at this endpoint
var allChapters = api.Chapters.ListAll(new() {
    Manga = "fc0a7b86-992e-4126-b30f-ca04811979bf"
});

await foreach(var chap in allChapters)
{
    Console.WriteLine("Chapter Title: {0}", chap.Attributes.Title);
}

Before this would have required manually iterating through each of the available pages of chapters, but I've handled that logic for you and it takes rate-limits into consideration. You can change how the library handles rate-limits with the optional parameters on the methods.

The biggest change in this update (and the thing that took the most time) was adding all of the documentation comments to ensure the Nuget package has intellisense comments in it. So now when hovering over API methods in your compatible IDE, you will get a description of what the method does and what the parameters mean. This can be useful for some of the less well documented or named methods / parameters. This took about 5 hours to do and resulted in 901 warnings in VS when I first implemented it.

image.png


Here is what the intellisense comments look like:
image.png


Another useful snippet I added was the Updates poll example. I use this code in my CardboardBox bot to send a discord message whenever manga that I'm interested in reading get new chapters. You can find the snippet and an example in the libraries github repo.

Some of the other updates include bug fixes:
  • DateTimes are now formatted properly in filters
  • The ChaptersFilter now defaults to 100 items per request (500 was too many)
  • Included default resolver for Data-Saver URLs
I'm also working on a typescript version of this API, but my motivation to work on it is relatively low as there are other solutions out there. I plan for it to follow a similar design to this one as I like the layout. If you think this might be useful or want to use it, let me know. You can find my progress so far on github.

If you're curious about more details, feel free to reply here, DM me on discord or checkout the commit details.
 
Last edited:
  • Like
Reactions: rdn
Group Leader
Joined
Feb 1, 2023
Messages
20
Not sure if anyone is using this library, but if you updated to the latest version of the nuget package (1.0.15), there is semi-breaking change:
If you use the dependency injection extension method .AddMangaDex(), you will need to also chain .AddJson() and .AddCardboardHttp() as these packages are no-longer auto registered.

Your code would need to now look something like this:

C#:
using CardboardBox.Http;
using CardboardBox.Json;
using MangaDexSharp;
using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
...
services
    .AddCardboardHttp()
    .AddJson()
    .AddMangaDex()
The reason for this is two fold; It should have never auto-injected the Json and Http packages by default without the users explicit permission, and when using conflicting versions of those packages (the http package is for doing API requests and the Json package is for abstracting out JSON serialization logic) the MangaDexSharp library just does not work.
People who use the MangaDex.Create() method of creating an API instance need make no change, as it is auto registered there as the service collection is made in an isolated scope.
 
Group Leader
Joined
Feb 1, 2023
Messages
20
If you're receiving sporadic 400 Bad Request responses from the API, try updating to the latest version! I believe I've fixed the issue.

I've also added the ability to override the User-Agent sent on all API requests via the library, you can specify it anywhere that you specify tokens or API urls:

C#:
//With MangaDex.Create():
var api = MangaDex.Create(userAgent: "Some-Fancy-User-Agent");

//With DI services:
services
    .AddMangaDex("Some Token", userAgent: "Some-Fancy-User-Agent");

//With an ICredentialsService
public class SomeCredsService : ICredentialsService
{
    ...
    public string UserAgent => "Some-Fancy-User-Agent";
    ...

}

//From configuration file
{
    "Mangadex": {
        "Token": "Some-Token",
        "UserAgent": "Some-Fancy-User-Agent"
    }
}

I've also got a semi-working version of the new custom-list-v2, however, I won't release that as the nuget package until V2 goes live on api.mangadex.org. I may do a beta release if there is interest.

Let me know if you have any questions, comments or concerns.

Some more things:
If you want to override how the library makes any API request, you can now override the IMdApiService in the dependency injection services and it will effect every request the library makes.
 

rdn

Forum Admin
Staff
Developer
Joined
Jan 18, 2018
Messages
281
Could you add a disclaimer that User-Agent spoofing is discouraged? As in, pretending to be a browser and thus hiding the fact that its automated traffic will get people banned, at least a comment that warns about that would certainly help people out
 
Group Leader
Joined
Feb 1, 2023
Messages
20
Could you add a disclaimer that User-Agent spoofing is discouraged? As in, pretending to be a browser and thus hiding the fact that its automated traffic will get people banned, at least a comment that warns about that would certainly help people out

I have added a notice at the top of the main readme on the GitHub
IMG_0919.png

Does that work?
 
  • Love
Reactions: rdn
Yuri Enjoyer
Staff
Developer
Joined
Feb 16, 2020
Messages
463
That's fine yes; didn't need to be this big either tbh.

We will overtime block more and more spoofed UAs automatically anyway (to combat malicious bots and scrapers), so it is really more to avoid people's stuff breaking. And there is indeed no reason to spoof your UA to us (if it's not malicious), as we do not filter for it in the first place.

Tbh 2 lines saying "hey, eventually they'll block you if you spoof it so don't cry then" (in a more polite way) is good enough
 
Group Leader
Joined
Feb 1, 2023
Messages
20
Another slightly breaking change in v1.0.18 that was released today.

It was brought to my attention that when the API returned an error code (non 2xx status code), the library would throw an exception and subsequently hide the returned error body. This has been fixed and now the library will return the results back.
There is also a new property on the root objects returned by the library. ErrorOccurred which is just short hand for Result == "error".

Since this changes the default behavior of the application, there is a way to update while opting out of this behaviour. You can set the throwOnError field on any of the configuration methods to true and it will keep throwing exceptions instead.

C#:
var api = MangaDex.Create();
var chapter = await api.Chapter.Get("not-a-chapter-id");
Console.WriteLine("Error Occurred: " + chapter.ErrorOccurred); //"Error Occurred: true"
Console.WriteLine("Error Count: " + chapter.Errors.Length); //1
...
var api = MangaDex.Create(throwOnError: true);
var chapter = await api.Chapter.Get("not-a-chapter-id"); //This throws an exception

You can read more about the solution in the issue or in the commit. This also required a change to the underlying CardboardBox.Http library that handles the XHR requests in C#.
 
Group Leader
Joined
Feb 1, 2023
Messages
20
A super late update, but an update none-the-less!
Personal API Clients token resolution methods are now supported by MD# v1.1.0!

You can fetch access tokens for your personal API clients with 2 different methods; either via Configuration or Manual specification.

Configuration:
You will need to edit your configuration file to include some new options:
JSON:
{
    "MangaDex": {
        "ClientId": "<your-personal-client-id>",
        "ClientSecret": "<your-personal-client-secret>",
        "Username": "<your-mangadex-username>",
        "Password": "<your-mangadex-password>"
    }
}
You can also use environment variables since it supports general IConfiguration options

Once you've specified the configuration options you can request the auth tokens (and refresh them) like so:
C#:
var services = new ServiceCollection()
    //Add your configuration file however you normally do:
    .AddConfiguration(SomeIConfigurationObject)
    .AddMangaDex()
    .BuildServiceProvider();

var client = services.GetRequiredService<IMangaDex>();
var token = await client.Auth.Personal();
var me = await client.User.Me(token.AccessToken);

//Then you can refresh it like so:
var newToken = await client.Auth.Refresh(token.RefreshToken);

Manually:
You can also specify all of your configuration manually in the request methods:

C#:
string clientId = "<your-personal-client-id>",
       clientSecret = "<your-personal-client-secret>",
       username = "<your-mangadex-username>",
       password = "<your-mangadex-password>";

var client = MangaDex.Create();
var token = await client.Auth.Personal(clientId, clientSecret, username, password);
var me = await client.User.Me(token.AccessToken);

//Then you can refresh it like so:
var newToken = await client.Auth.Refresh(token.RefreshToken, clientId, clientSecret);

You can see all of the changes in this commit.
Since MangaDex doesn't support public clients yet, I will implement them once they become available.
If you have any issues, comments or concerns, feel free to reply here or open an issue on the repo!
 

Users who are viewing this thread

Top