thedrummeraki / mangadex

Your next (unofficial) favourite Ruby gem for interacting with Mangadex.org
https://rubygems.org/gems/mangadex
MIT License
6 stars 1 forks source link
gem mangadex mangadex-api rails unofficial

Docker Image CI

Mangadex

Welcome to mangadex, your next favourite Ruby gem for interacting with Mangadex.

Important information

By using this gem you accept:

These are Mangadex's rules, please follow them.

Installation

Add this line to your application's Gemfile:

gem 'mangadex'

And then execute:

$ bundle

Or install it yourself as:

$ gem install mangadex

Usage

Please note that I tried my best to follow Mangadex's naming conventions for their documentation. Track the progress here in an issue. Although a work a in progress, feel free to check this out.

Basic Usage

Here's a couple of cool things you can do with the gem:

Get a list of manga

response = Mangadex::Manga.list
manga = response.data # Array of #<Mangadex::Manga>

Get a manga by id, with cover_art

manga_id = 'd86cf65b-5f6c-437d-a0af-19a31f94ec55'
response = Mangadex::Manga.get(manga_id, includes: :cover_art)
entity = response.data # Object of #<Mangadex::Manga>

# Original size
entity.cover_art.image_url(size: :original)
entity.cover_art.image_url(size: :medium)
entity.cover_art.image_url(size: :small) # default size

Get a manga's chapter list, ordered by volume and chapter number

manga_id = 'd86cf65b-5f6c-437d-a0af-19a31f94ec55'
manga_response = Mangadex::Manga.get(manga_id, includes: :cover_art)
entity = manga_response.data

chapter_response = Mangadex::Chapter.list(
  manga: entity.id,
  order: { volume: 'asc', chapter: 'asc' },
  translated_language: 'en',
)
chapters = chapter_response.data # Array of #<Mangadex::Chapter>

Get a chapter's pages

chapter_id = 'e7bb1892-7f83-4a89-bccc-0d6d403a85fc'
chapter = Mangadex::Chapter.get(chapter_id).data
pages = chapter.page_urls # Data saver true by default

Search for manga by title

response = Mangadex::Manga.list(title: 'Ijiranaide nagatoro')
found_manga = response.data

Authenticate

with a block...:

Mangadex::Auth.login(username: 'username', password: 'password') do |user|
  # `user` is of type Mangadex::Api::User
  puts(user.mangadex_user_id)
  puts(user.session)
  puts(user.refresh)
  puts(user.session_valid_until)
end

...or inline...:

# `user` is of type Mangadex::Api::User
user = Mangadex::Auth.login(username: 'username', password: 'password')

puts(user.mangadex_user_id)
puts(user.session)
puts(user.refresh)
puts(user.session_valid_until)

You can access the authenticated user by using context:

user = Mangadex.context.user

Refresh the user's token

Mangadex.context.user.refresh_session! do |user|
  # `user` is of type Mangadex::Api::User
  puts(user.mangadex_user_id)
  puts(user.session)
  puts(user.refresh)
  puts(user.session_valid_until)
end

Create an public MDList, add then remove a manga

Mangadex::Auth.login(...)
response = Mangadex::CustomList.create(name: 'My awesome list!', visibility: 'public')
custom_list = response.data

manga_id = 'd86cf65b-5f6c-437d-a0af-19a31f94ec55'
# Add the manga
custom_list.add_manga(manga_id)

# Remove the manga
custom_list.remove_manga(manga_id)

# Get manga list
manga = custom_list.manga_details.data # Array of #<Mangadex::Manga>

Are you on Rails?

This gem tries its best to be agnostic to popular frameworks like Rails. Here's however a couple of things to can do to integrate the gem to your project.

First, add the gem to your Gemfile.

Configurating the gem

Create a initilizer file to config/initializers/mangadex.rb. You can add the following:

Mangadex.configure do |config|
  # Override the default content ratings
  config.default_content_ratings = %w(safe suggestive)

  # Override the Mangadex API URL (ie: proxy)
  config.mangadex_url = 'https://my-proxy-mangadex-url.com'
end

Authenticate your users

This could be useful if you want to support authentication. You will need to persist your user's session, refresh token and session expiry date.

Persist the user information

If you haven't done so, create your user.

class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :mangadex_user_id, null: false
      t.string :username
      t.string :session
      t.string :refresh
      t.datetime :session_valid_until

      t.timestamps
    end
  end
end

Already created your User class? Make sure it has all of the following:

If anything is missing, create a migration.

Authentication flow on the controller

Add these methods to your controller's helper (ie: ApplicationHelper):

module ApplicationHelper
  def current_user
    @current_user ||= User.find_by(id: session[:id])
  end

  def logged_in?
    current_user.present?
  end

  def log_in(user)
    # `user` is an instance of your `User` class
    session[:id] = user.id
  end

  def log_out
    # Logout from Mangadex
    Mangadex::Auth.logout

    # Remove the session
    session.delete(:id)
  end
end

First make sure ApplicationController includes the helper above

class ApplicationController < ActionController::Base
  include ApplicationHelper

  # ...
end

We recommend creating a controller for authentication. Here's how you can implement the login and logout actions:

# app/controllers/session_controller.rb
class SessionController < ApplicationController
  # GET /login
  def new
    # render the login form
  end

  # POST /login
  def create
    username = params[:username]
    password = params[:password]

    # You can also use `email` instead of `username` to log in
    user = Mangadex::Auth.login(username: username, password: password) do |mangadex_user|
      # Find the user by mangadex user id (or initialize if it doesn't exist)
      our_user = User.find_or_initialize_by(mangadex_user_id: mangadex_user.mangadex_user_id) do |new_user|
        new_user.username = mangadex_user.data.username
      end

      # Update the session info data
      our_user.session = mangadex_user.session
      our_user.refresh = mangadex_user.refresh
      our_user.session_valid_until = mangadex_user.session_valid_until

      # ...then save the user
      our_user.save!
      our_user
    end

    # `user` will be an instance of your `User` class
    # Now, we can log in then redirect to the root.
    log_in(user)
    redirect_to(root_path)
  rescue Mangadex::Errors::AuthenticationError => error
    # See https://api.mangadex.org/docs.html to learn more about errors
    Rails.logger.error(error.response.errors)

    # Handle authentication errors here
  end

  # DELETE /logout
  def destroy
    log_out

    redirect_to(root_path)
  end
end

Finally, add the routes.

# config/routes.rb
Rails.application.routes.draw do
  # ...
  get '/login' => 'session#new'
  post '/login' => 'session#create'
  delete '/logout' => 'session#destroy'
end

Protected resources

Here's an example of a controller that requires every action to be logged in. This is based on the steps above.

class ProtectedController < ApplicationController
  before_action :ensure_logged_in!

  private

  def ensure_logged_in!
    return if logged_in?

    redirect_to(login_path) # go to /login
  end
end

We're going with managing (list, create, show, edit, delete) MDLists (ie: custom lists). We're not using strong params below to keep things simple, but you should, especially when mutating data (ie: creating and editing).

class CustomListsController < ProtectedController
  # GET /custom_list
  def index
    @custom_lists = Mangadex::CustomList.list
  end

  # GET /custom_list/new
  def new
    # new custom list form
  end

  # POST /custom_list
  def create
    @custom_list = Mangadex::CustomList.create(
      name: params[:name],
      visibility: params[:visibility],
      manga: params[:manga], # Manga ID
    )
  end

  # GET /custom_list/<id>
  def show
    @custom_list = Mangadex::CustomList.get(params[:id])
  end

  # GET /custom_list/<id>/edit
  def edit
    @custom_list = Mangadex::CustomList.get(params[:id])
    # edit custom list form
  end

  # PUT /custom_list/<id>
  # PATCH /custom_list/<id>
  def update
    # Note: when updating the custom list, be sure to pass in
    # the current version number!
    @custom_list = Mangadex::CustomList.update(
      params[:id],
      {
        name: params[:name],
        visibility: params[:visibility],
        manga: params[:manga],
        version: params[:version].to_i,
      }
    )
  end

  # DELETE /custom_list/<id>
  def destroy
    Mangadex::CustomList.delete(params[:id])
  end
end

Development

Docker

You can use Docker to get started with dev work on the repo. After installing Dcoker, you can build the image:

docker build -t mangadex .

Then run the ruby console with the gem loaded:

docker run --rm -it mangadex:latest

You can also log in directly when setting the MD_USERNAME and MD_PASSWORD (or MD_EMAIL) environment variables:

docker run --rm -e MD_USERNAME=username -e MD_PASSWORD=password -it mangadex:latest

Docker Compose

If it's simpler, you can simply use Compose and get started quickly.

Note: You may have to use docker-compose if you're using Compose V1. This project should be compatible with both Compose V1 and V2. See the Compose migration docs to learn more.

Build the image:

docker compose build

And run the ruby console with the gem loaded:

docker compose run gem

Create a docker-compose.override.yml to add environment secrets (and anything else you'd like to customize):

# docker-compose.override.yml

version: '3'
services:
  gem:
    environment:
      MD_USERNAME: username
      MD_PASSWORD: password

Running docker compose run gem, which launches the ruby console, will attempt logging in the user username.

Locally

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

You can also

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/thedrummeraki/mangadex. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Mangadex project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.