[PYTHON] [Completed] bot that posts the start notification of Nico Nico Live Broadcasting to Discord on discord.py

at first

This article is a continuation of the concept edition, so it is easy to understand if you also read it. [Concept] bot that posts the start notification of Nico Nico Live Broadcasting to Discord on discord.py

Problems to be solved

--You need to create a DB in PostgreSQL and have data in it ――If you have the setting value in the DB, isn't it necessary to rewrite the code and restart Heroku? ――I want to support not only community broadcasting but also channel broadcasting

DB table structure

setting table

--token: DiscordBot token --channel_id: The ID of the channel on which the bot posts notifications

token channel_id
XXXXXXXXXXXXXXXXXXXXXXXXXXXXX 0000000000000000

target table

--community: The community number you want to monitor --comment: For memo (not used on the system)

id community comment
1 co1520016 BotTV
2 co117683 myCommunity

logs table

--live: Broadcast ID notified

id live
1 lv0000000
2 lv2222222

code

discordbot.py


import requests
import os.path
import re
import discord
import asyncio
import os, psycopg2
import json
from bs4 import BeautifulSoup

path = "PATH"
port = "5432"
dbname = "DB_NAME"
user = "USER"
password = "PASSWORD"
conText = "host={} port={} dbname={} user={} password={}"
conText = conText.format(path,port,dbname,user,password)
connection = psycopg2.connect(conText)

cur = connection.cursor()
sql = "select token,channel_id from settings"
cur.execute(sql)
result = cur.fetchone()

#Get token
TOKEN = result[0]
#Get channel ID
CHANNEL_ID = result[1]

#Get the community you want to check from the target table
def getTarget():
    targetCommunitys = []
    sql = "select community from target"
    cur.execute(sql)
    for row in cur:
        targetCommunitys.append(row[0])
    return targetCommunitys

#Broadcast ID from the broadcast URL(lvXXXXXXX)Extraction
def liveIdExtraction(liveURL):
    repatter = re.compile('lv[0-9]+')
    return repatter.search(liveURL).group()

#Get broadcast title from broadcast URL
def getLiveTitle(liveURL):
    r = requests.get(liveURL)
    soup = BeautifulSoup(r.content, "html.parser")
    for meta_tag in soup.find_all('meta', attrs={'property': 'og:title'}):
        return meta_tag.get('content')

#Obtaining the broadcaster name from the broadcast URL
def getLiveName(liveURL):
    r = requests.get(liveURL)
    soup = BeautifulSoup(r.content, "html.parser")
    return soup.find("span",{"class":"name"}).text

#logs Returns False if there is no search in the table True
def searchList(liveURL):
    liveLV = liveIdExtraction(liveURL)
    cur = connection.cursor()
    sql = "SELECT count(*)  FROM logs WHERE live = '" + liveLV + "'"
    cur.execute(sql)
    result = cur.fetchone()
    if int(result[0]) > 0:
        return True
    else:
        return False

#Broadcast ID added to logs table
def addList(liveURL):
    liveLV = liveIdExtraction(liveURL)
    cur = connection.cursor()
    sql = "insert into logs(live) values('"+ liveLV + "');"
    cur.execute(sql)
    connection.commit()

#Generate the objects needed for the connection
client = discord.Client()

#Processing that operates at startup
@client.event
async def on_ready():

    while(True):
        #Repeat for the number of target communities
        targetCommunitys = getTarget()
        for targetCommunity in targetCommunitys:
            #Set URL
            r = requests.get("https://live.nicovideo.jp/watch/" + targetCommunity)

            #Check the community TOP page
            soup = BeautifulSoup(r.content, "html.parser")
            result = soup.find('meta', attrs={'property': 'og:url', 'content': True})
            #Broadcast URL acquisition
            liveURL = result['content']

            #Search in the list and do not process if the broadcast ID has already been processed
            if searchList(liveURL) is False:
                #Broadcast title acquisition
                liveTitle = getLiveTitle(liveURL)
                #Broadcaster name acquisition
                liveName = getLiveName(liveURL)

                #Send to Discord
                channel = client.get_channel(int(CHANNEL_ID))
                await channel.send(liveName + 'Has started delivery\n\n' + liveTitle + '\n' + liveURL)

                #Broadcast ID postscript
                addList(liveURL)

        #Channel search
        url = 'https://api.search.nicovideo.jp/api/v2/live/contents/search'
        ua = 'Twitter @fctokyo1016'
        headers = {'User-Agent': ua}
        params = {
            'q': 'BoxTV',
            'targets': 'title,description,tags',
            '_sort': '-openTime',
            '_context': ua,
            'fields': 'contentId,channelId,liveStatus,title',
            'filters[channelId][0]': '2640777',
            'filters[liveStatus][0]': 'onair'
        }
        #request
        res = requests.get(url, headers=headers, params=params)
        #Store the acquired json in the lists variable
        lists = json.loads(res.text)

        if lists['meta']['totalCount'] > 0:
            for data in lists['data']:
                if searchList(data['contentId']) is False:
                    #Send to Discord
                    channel = client.get_channel(int(CHANNEL_ID))
                    await channel.send('Started distribution on the channel\n\n' + data['title'] + '\nhttps://nico.ms/' + data['contentId'])

                    #Broadcast ID postscript
                    addList(data['contentId'])

        #Wait 1 minute
        await asyncio.sleep(60)

#Connect to Discord
client.run(TOKEN)

What you are doing

--Get the target community and other settings from the DB --Scraping the community page of Nico Nico Live Broadcasting to get the broadcasting URL ――In addition, hit the API of the live channel broadcast to search if the broadcast has started. --Notify Discord --Leave the notified broadcast in the DB so that it will not be notified again

Various setting values for connecting to DB

discordbot.py


path = "PATH"
port = "5432"
dbname = "DB_NAME"
user = "USER"
password = "PASSWORD"
conText = "host={} port={} dbname={} user={} password={}"
conText = conText.format(path,port,dbname,user,password)
connection = psycopg2.connect(conText)

Get the token and Discord channel ID from the settings table

discordbot.py


cur = connection.cursor()
sql = "select token,channel_id from settings"
cur.execute(sql)
result = cur.fetchone()

#Get token
TOKEN = result[0]
#Get channel ID
CHANNEL_ID = result[1]

Get the community you want to check from the target table and return it as an array

discordbot.py


#Get the community you want to check from the target table
def getTarget():
    targetCommunitys = []
    sql = "select community from target"
    cur.execute(sql)
    for row in cur:
        targetCommunitys.append(row[0])
    return targetCommunitys

Various data are obtained by scraping from the broadcast URL

discordbot.py


#Broadcast ID from the broadcast URL(lvXXXXXXX)Extraction
def liveIdExtraction(liveURL):
    repatter = re.compile('lv[0-9]+')
    return repatter.search(liveURL).group()

#Get broadcast title from broadcast URL
def getLiveTitle(liveURL):
    r = requests.get(liveURL)
    soup = BeautifulSoup(r.content, "html.parser")
    for meta_tag in soup.find_all('meta', attrs={'property': 'og:title'}):
        return meta_tag.get('content')

#Obtaining the broadcaster name from the broadcast URL
def getLiveName(liveURL):
    r = requests.get(liveURL)
    soup = BeautifulSoup(r.content, "html.parser")
    return soup.find("span",{"class":"name"}).text

Check the logs table to see if Discord has already been notified

discordbot.py


#logs Returns False if there is no search in the table True
def searchList(liveURL):
    liveLV = liveIdExtraction(liveURL)
    cur = connection.cursor()
    sql = "SELECT count(*)  FROM logs WHERE live = '" + liveLV + "'"
    cur.execute(sql)
    result = cur.fetchone()
    if int(result[0]) > 0:
        return True
    else:
        return False

Log the notification in the logs table

discordbot.py


#Broadcast ID added to logs table
def addList(liveURL):
    liveLV = liveIdExtraction(liveURL)
    cur = connection.cursor()
    sql = "insert into logs(live) values('"+ liveLV + "');"
    cur.execute(sql)
    connection.commit()

It is a confirmation of the channel live broadcast that was not the concept edition. I am using the API of Nico Nico Live Broadcasting niconico Content Search API Guide

discordbot.py


        #Channel search
        url = 'https://api.search.nicovideo.jp/api/v2/live/contents/search'
        ua = 'Twitter @fctokyo1016'
        headers = {'User-Agent': ua}
        params = {
            'q': 'BoxTV',
            'targets': 'title,description,tags',
            '_sort': '-openTime',
            '_context': ua,
            'fields': 'contentId,channelId,liveStatus,title',
            'filters[channelId][0]': '2640777',
            'filters[liveStatus][0]': 'onair'
        }
        #request
        res = requests.get(url, headers=headers, params=params)
        #Store the acquired json in the lists variable
        lists = json.loads(res.text)

        if lists['meta']['totalCount'] > 0:
            for data in lists['data']:
                if searchList(data['contentId']) is False:
                    #Send to Discord
                    channel = client.get_channel(int(CHANNEL_ID))
                    await channel.send('Started distribution on the channel\n\n' + data['title'] + '\nhttps://nico.ms/' + data['contentId'])

                    #Broadcast ID postscript
                    addList(data['contentId'])

Recommended Posts

[Completed] bot that posts the start notification of Nico Nico Live Broadcasting to Discord on discord.py
[Concept] bot that posts the start notification of Nico Nico Live Broadcasting to Discord on discord.py
Make a BOT that shortens the URL of Discord
Create a bot that only returns the result of morphological analysis with MeCab on Discord
Let's execute the command on time with the bot of discord
Get comments on Nico Nico Live Broadcasting
Create a bot that posts the number of people positive for the new coronavirus in Tokyo to Slack
I tried to make a translation BOT that works on Discord using googletrans
Looking back on the history of expressions that return sum of square to Pythonic
I created a Discord bot on Docker that reports the number of corona infected people in Tokyo at a specified time.