🧑‍🎨

Pixivのアートワークを取得して貼り付けるDiscordBotを作る

2021/11/22に公開

はじめに

DiscordでpixivのURLを貼った際にアートワークが半分程度しか表示されないことにモヤモヤしていたのでアートワークを取得して貼り付けるbotを作成しました。

https://www.bunka.go.jp/seisaku/chosakuken/seidokaisetsu/gaiyo/chosakubutsu_jiyu.html
https://qiita.com/nezuq/items/9e297d0e3468c24e8afa

概要

技術構成

使用言語
Python - Discord.pyライブラリとPixivpyライブラリを使用したいために選定

使用ライブラリ
Discord.py
Pixivpy

使用ツール
Retrieving Auth Token (with Selenium)

できました

https://github.com/Kahra029/pixivbot
ツールを使用の際はconfig.jsonpixiv_refresh_tokendiscord_tokenをご自身の情報に上書きしてください。

チャート

  • Pixivログイン情報の取得
  • アートワークの取得
  • DiscordBotの有効化

Pixivログイン情報の取得

ツールを使用してご利用のpixivアカウントのrefresh tokenを取得します。
取得の方法は下記ページを参考にしてください。
また、このツールを使用する用のアカウントを別に取得することをお勧めいたします。
https://gist.github.com/upbit/6edda27cb1644e94183291109b8a5fde

アートワークの取得

まずpixivpyをインストールします。

pip install pixivpy

これでライブラリを使用する準備はできました。
引数として受け取ったPixivのアートワークIDをもとにアートワークを取得します。
ライブラリが充実しているので難しいことはありませんでした。

pixivwork.py
import json
from pixivpy3 import *

class PixivData():
    def __init__(self):
        with open('config.json', 'r') as f:
            config = json.load(f)
            self.__pixivToken = config['pixiv_refresh_token']
            self.__downloadPath = config['download_path']
        self.__pixiv = AppPixivAPI()

    @property
    def pixivToken(self):
        return self.__pixivToken

    @property
    def downloadPath(self):
        return self.__downloadPath

    @property
    def pixiv(self):
        return self.__pixiv

class PixivWork():
    def __init__(self, artworkId):
        self.__artworkId = artworkId

    @property
    def artworkId(self):
        return self.__artworkId

    @artworkId.setter
    def artworkId(self, val):
        self.__artworkId = val

    def getArtwork(self):
        p = PixivData()
        p.pixiv.auth(refresh_token = p.pixivToken)
        data = p.pixiv.illust_detail(self.artworkId)
        artwork = data.illust.image_urls.large
        exteniton = artwork[artwork.find('master1200.'):]
        fileName = f'{self.artworkId}{exteniton}'
        p.pixiv.download(artwork, path = p.downloadPath, name = fileName)
        result = {
            'title': data.illust.title,
            'user': data.illust.user.name,
            'fileName': fileName
        }
        return result

    def getArtworks(self):
        p = PixivData()
        p.pixiv.auth(refresh_token = p.pixivToken)
        data = p.pixiv.illust_detail(self.artworkId)
        artworks = data.illust.meta_pages
        i = 0
        for artwork in artworks: 
            imageUrl = artwork.image_urls.large
            exteniton = imageUrl[imageUrl.find('master1200.'):]
            artworkName = f'{self.artworkId}{exteniton}'
            fileName = f'{str(i)}_{artworkName}'
            p.pixiv.download(imageUrl, path = p.downloadPath, name = fileName)
            i = i + 1
        
        result = {
            'title': data.illust.title,
            'user': data.illust.user.name,
            'fileName': artworkName,
            'pageCount': data.illust.page_count,
        }
        return result

DiscordBotの有効化

Botアカウント作成に従いDiscordBotを有効化します。
bot作成後、config.jsondiscord_tokenを変更してください。
続いてライブラリdiscord.pyをインストールします。

pip install discord.py

bot部分はクイックスタートを基に作成します。
メッセージで受け取ったURLを分解してアートワークIDを取得しpixivworkに渡します。
URLの前に!allメッセージが入っている場合は全てのイメージを出力するようにしました。

メッセージはembedの形式で多少見栄えがよく出力されるようにしました。
特に難しいことはしていないのですが、embedにイメージを挿入する際にローカルで保存したファイルを送信する場合はattachment//をつけることを忘れないようにしましょう。詳しくはこちらをご覧ください。

bot.pyimport os
import re
import json
import discord
from libs.pixivwork import PixivWork
from libs.calendar import Calendar

with open('config.json', 'r') as f:
    config = json.load(f)
discordToken = config['discord_token']
artworkUrl = config['artwork_url']

client = discord.Client(ws = int(os.environ.get('PORT', 5000)))

@client.event
async def on_ready():
    print('READY')

@client.event
async def on_message(message):
    content = message.content
    if re.search(artworkUrl, content):
        if re.search('#manga', content):
            content = content.replace('#manga', '')
        
        if re.search('!all ', content):
            content = content.replace('!all ', '')
            artworkId = content[len(artworkUrl):]
            work = PixivWork(artworkId)

            result = work.getArtworks()
            embed=discord.Embed(title=result["user"], description=result["title"])
            for i in range(result["pageCount"]):
                artworkPath = f'{i}_{result["fileName"]}'
                file = discord.File(artworkPath)
                embed.set_image(url=f'attachment://{artworkPath}')
                if i == 0 :
                    await message.channel.send(file=file, embed=embed)
                else:
                    await message.channel.send(file=file)
                os.remove(artworkPath)
        else:
            artworkId = content[len(artworkUrl):]
            work = PixivWork(artworkId)
            result = work.getArtwork()
            file = discord.File(fp=result["fileName"],filename=result["fileName"])
            embed=discord.Embed(title=result["user"], description=result["title"])
            embed.set_image(url=f'attachment://{result["fileName"]}')
            await message.channel.send(file=file, embed=embed)
            os.remove(result["fileName"])

client.run(discordToken)

以上です。

おわりに

pythonを書いたのは初めてだったのですがライブラリのヘルプが充実していたのでそこまで苦労せずに作成できました。
Botから画像の送信の場合embedの表示で画像の埋め込みが一枚までしか送れないようなので、いずれはDiscordWebhookを使用する方法も実装したいと思います。

以上、ご覧いただきありがとうございました。

Discussion