Discordに簡易的なアフィリエイト的システムを構築するよ
どもども、連日のDiscordBOT記事です。
今回はDiscordにアフィリエイト的な機能を実装してみようと思います。今回の記事で実装するのは、サーバーへの招待数によってサーバー内の役割を自動付与する機能です。
これは今度記事にしようと思っている、とあるサーバーで実装されていた機能なのですが、面白そうだったので、自分でも実装してみました。もしかしたら、より簡単・正確に実装する方法があるのかもしれませんので、あくまで趣味で作ったということをご了承ください。
OS : Ubuntu 16.04 LTS, MacOS
言語 : Python3.6.0
DB : MySQL
Contents
0. 方法
アフィリエイトの機能ではありませんが、Discordには招待状の仕組みがあり、サーバーへ招待した数が画面上で確認することができます。しかし、ここで表示される招待数は、サーバーに出入りすることにより、いくらでも水増しすることができてしまいます。そんな仕様でアフィリエイトを行おうとすると、誰でも最高の報酬を獲得することができてしまいます。
というわけで今回は上記の招待状の機能を使いつつ、BOTとデータベースを活用することでより正確なアフィリエイトシステムを構築します。機能としては、招待数によってサーバー内のRoleが変化するような動きを作ります。
1. 下準備
例のごとくDiscordのBOTを作成するので、公式サイトからBOTの登録をやります。やり方は、以前の記事に書いてあるので、そちらをご覧ください。こちらを参考にBOTトークンの獲得までやってください。
次に、データベースの準備です。自分はすでにMAMPを導入していたのでデータベース環境は整っていました。なので本記事ではデータベース環境の構築は省略させてもらいます。とりあえず、Pythonのコードからデータベースを扱えるように環境を整えてください。
テーブルはユーザーテーブル(user)と招待状テーブル(invite)を用意します。それぞれのテーブルは以下の感じの設計をしてみました。
1 2 3 4 5 6 7 8 9 10 |
テーブル名 : user id int unsigned auto_increment 主キー user_id char user_name char テーブル名 : invite id int unsigned auto_increment 主キー user_id char invited int accept int |
データベースの構造については、個人的に納得していません。が、今回は気にしません。
2. プログラムを書く
では本記事のメインになる、コードを掲載していきます。今回は機能によってファイルを分割しているので、ちょっと件数が増えてしまいましたが、ただ実行したい人は単純にコピペしていけば大丈夫です。
まずは、データベースの情報やDiscordのトークンなどを記述しておくものです。さらに、招待数による役割(Role)の変更を定義もこのファイルでやっていきます。もし、役割の変更の機能を別のものに変えるのであれば、その部分は不要です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#coding: utf-8 # SERVER ID # SERVERページのURL # https://discordapp.com/channels/[この部分←ここ]/[ROOM-ID] DISCORD_SERVER_ID = "0000000000000000000000" # BOT TOKEN DISCORD_BOT_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxx" # DB INFORMATION DB_HOST = "localhost" DB_USER_NAME = "hoge" DB_PASSWORD = "fuga" DB_DB = "discord_bot_database_name" # ROLE RANK # 一番下の役職名"@everyone"の代わりになる役職名 LOWEST_ROLE_NAME = "rank-0" # [ランクの高さ, ランク名, 必要招待人数]のリストを格納するリスト # ランクの高さはDiscordの役職登録画面での高さに対応 ROLE_RANK_TABLE = [ [0, "@everyone", 0], [2, "rank-1", 1], [3, "rank-2", 2], [4, "rank-3", 3], [5, "rank-4", 4], ] |
これらの設定ファイルをご自身の環境や実現したい招待数に対応するように書き換えてください。以降のコードでこのファイルを読み込んでいきますので、ちゃんと書き換えておいてください。
今回はデータベースをいじることが多いので、それらの操作をまとめて関数化しておきます。以降のコードでデータベースを使用するときは、ここで定義した関数を使用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
#coding: utf-8 import _config import MySQLdb _mysql = MySQLdb.connect(host=_config.DB_HOST, user=_config.DB_USER_NAME, passwd=_config.DB_PASSWORD, db=_config.DB_DB) def select_user(user_id): cursor = _mysql.cursor() try: cursor.execute('SELECT * FROM user WHERE user_id = '+ str(user_id)) result = cursor.fetchall() finally: cursor.close() return result def select_invite(user_id): cursor = _mysql.cursor() try: cursor.execute('SELECT * FROM invite WHERE user_id = '+ str(user_id)) result = cursor.fetchall() finally: cursor.close() return result def insert_user(user_id, user_name): cursor = _mysql.cursor() try: cursor.execute("INSERT INTO user (user_id, user_name) VALUES ("+ str(user_id) +", '"+ user_name +"')") _mysql.commit() except: pass cursor.close() def insert_invite(user_id, invite): cursor = _mysql.cursor() try: cursor.execute("INSERT INTO invite (user_id, invited) VALUES ("+ str(user_id) +", "+ str(invite) +")") _mysql.commit() except: pass cursor.close() def update_invited(user_id, invited, add_accept=1): cursor = _mysql.cursor() cursor.execute("UPDATE invite SET invited = "+ str(invited) +", accept = accept + "+ str(add_accept) +" WHERE user_id = "+ str(user_id)) _mysql.commit() cursor.close() |
基本的にSELECT文とINSERT文をいちいち書くのがめんどくさかっただけなので、必ずこのようなファイルを作る必要なはないのですが、管理はしやすい気がするので…自己満足です。
次は、役職関係の関数をまとめたものです。もし役職変更の機能を別のものに変更する場合は、もちろん不要ですので、ご自身のやりたいことに合わせて作成してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#coding: utf-8 import discord import _config # 役職の変更 async def change_role(client, member, role_name): role = discord.utils.get(member.server.roles, name=role_name) await client.add_roles(member, role) # 現在の紹介数を引数として、対応するランクの情報をリストで返す # return [役職のポジション, 役職名, 紹介必要数] def get_real_role_by_invited(num_invited): for _i in _config.ROLE_RANK_TABLE[::-1]: if _i[2] <= num_invited: return _i |
最後に、本記事で最も大切なコードである、招待状の獲得・確認・招待数の登録・確認を行う機能を持つBOTの本体コードです。実際にプログラムを実行する際は、このコードを指定して実行します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
#coding: utf-8 import discord client = discord.Client() import _role import _config import _database @client.event async def on_ready(): _server = discord.utils.get(client.servers, id=_config.DISCORD_SERVER_ID) # データベースにユーザを登録 members = _server.members for member in members: _database.insert_user(member.id, member.name) # データベースに招待状を登録 invites = await client.invites_from(_server) for invite in invites: # 招待状の期限が無限でないものは削除 if invite.max_age != 0: await client.delete_invite(invite) continue _database.insert_invite(invite.inviter.id, invite.uses) @client.event async def on_member_join(member): # 過去に登録したことがあるユーザーかを確認 if len(_database.select_user(member.id)) == 0: # 新規ユーザーなら新規登録 _database.insert_user(member.id) is_new_registered_member = True else: is_new_registered_member = False invites = await client.invites_from(member.server) for invite in invites: # 招待状の期限が無限でないものは削除 if invite.max_age != 0: await client.delete_invite(invite) continue # 招待状が未登録だったら登録 _invite = _database.select_invite(invite.inviter.id) if len(_invite) == 0: _database.insert_invite(invite.inviter.id, 0) invited = 0 else: invited = _invite[0][2] # 過去の招待数と異なるか確認 if invited == invite.uses: continue # 過去の招待数を更新 _database.update_invited(invite.inviter.id, invite.uses, 1 if is_new_registered_member else 0) # ランクアップの確認 & 更新 if is_new_registered_member: new_role = _role.get_real_role_by_invited(invited+1) _inviter = discord.utils.get(member.server.members, id=invite.inviter.id) if _inviter.top_role.position < new_role[0]: await _role.change_role(client, _inviter, new_role[1]) client.run(_config.DISCORD_BOT_TOKEN) |
このコードでやっているのは、招待状で誰かがサーバーに登録した瞬間に、DBに登録してある情報とDiscord上の招待数の差を獲得し、もし過去に登録してない人で招待数が増えていたのであれば、有効招待数を増加させます。そして、有効招待数が設定した値を超えていれば役職を変更するという動作をします。
以上でコードの掲載はおしまいです。もし役職の変更部分の機能を別のものにしたいのであれば、”ランクアップの確認アンド更新”の部分を書き換えればいいのではないかなと思います。
3. 注意点
本記事によって発生したいかなる損害も保証しかねます。また、掲載したコードは最適解ではないのでご了承ください。
今回紹介したプログラムは招待状の期限が無いものだけに制限しています。制限があるものはプログラムの実行時や招待時に削除されます。また、プログラムが実行されていない時に発生した招待は全て無効になってしまいます。Discordの仕様上、数ミリ秒単位で同時に登録がなされた場合、招待数が複数カウントされてしまう可能性があります。
コーディングで分からないことがあれば
プログラミングや環境構築で分からないことがあったら『teratail』というエンジニア特化型のQ&Aサービスがオススメです。自分もどうしても分からないことがあったら、時々質問しにいきますが、かなりニッチな質問にも意外と早く回答がつくのでとても頼もしいです。という宣伝でした。
おわりに
さて、ここまで頑張ってきました。Discordにアフィリエイト的なシステムを構築するのに、どれほどの需要があるのかはわかりませんが、面白そうだったので、実装・記事にしました。冒険心のある方は是非使ってみてね。