I have a Discord Bot and I want to send a message whenever a certain user uploads a video. I have had a look at the Youtube API (https://developers.google.com/youtube/v3/docs/videos) but have not found how to do what I want.
-
4You can check in this [documentation](https://developers.google.com/youtube/v3/guides/push_notifications) on how to subscribe to Push notification. It is stated here that the YouTube Data API (v3) supports push notifications via [PubSubHubbub](https://github.com/pubsubhubbub/), a server-to-server publish/subscribe protocol for Web-accessible resources. Notifications are pushed out to subscribers via HTTP webhooks, which is much more efficient than polling-based solutions. – KENdi Apr 11 '17 at 16:41
2 Answers
Well ..I do it using checking for the video every 1 minute and check if the video link(or id) is not equal to the last video then post the video in that particular channel you want to post to.
I use google-api-python-client
Firstly pip install google-api-python-client
from from googleapiclient.discovery import build
In your on_ready function
@client.event async def on_ready(): youtube=build('youtube','v3',developerKey='Enter your key here') req=youtube.playlistItems().list( playlistId='The Playlist id of the channel you want to post video i.e. the id of video playlist of the channel', part='snippet', maxResults=1 ) res=req.execute() vedioid=res['items'][0]['snippet']['resourceId']['videoId'] link="https://www.youtube.com/watch?v="+vedioid ch=await client.fetch_channel(the channel id from where im checking for the new video) await ch.send(link) yt.start()#Starting tasks loop which is made below for checking every minute if the new video is equal or unequal to old video link
Making the tasks loop for checking the video
@tasks.loop(seconds=60) async def yt(): youtube=build('youtube','v3',developerKey='Enter your key here') req=youtube.playlistItems().list( playlistId='The Playlist id of the channel you want to post video i.e. the id of video playlist of the channel', part='snippet', maxResults=1 ) res=req.execute() vedioid=res['items'][0]['snippet']['resourceId']['videoId'] link="https://www.youtube.com/watch?v="+vedioid ch=await client.fetch_channel(Fetching same channel from which you are checking for the video link) async for message in ch.history(limit=1):#looping through the channel to get the latest message i can do this using last message also but I prefer using channel.history if str(link) != str(message.content): ch2=await client.fetch_channel(the channel you want to post video to) await ch2.send(f'@everyone,**User** just posted a vedio!Go and check it out!\n{link}') await ch.send(link2)#this is important as after posting the video the link must also be posted to the check channel so that the bot do not send other link else: pass
So basically what Im doing is using a private channel to post the latest video of the bot as soon as it is ready because if by chance the bot goes offline in between and then comes online it posts the link to that channel then im making as tasks loop in which Im checking every minute that if the latest video link fof that youtube channel is not equal to the video link in my private channel that means the uploader has uploaded a video so post the video in the channel i wish to post.If its equal then do nothing i.e. pass
You can use a json file or a database if you are using instead of like I used channel to check for the video.It works fine.

- 21
- 2
Youtube provides a proper webhook api for this so that you do not need to use polling. You can read more about it here.
You will need a webserver to receive their authentication get request and following post requests that are sent whenever a video is published. Furthermore you need to send a get request to their server to subscribe after your webserver is running.
Showing the entire code including how to connect it to a bot would be too much for this answer. You can see the full code, including the bot in this github repo. Alternatively I made a youtube tutorial for this question which you can view here.
Below the code of the webserver and the get request in python:
# Function to start the web server async
async def web_server(self):
# This is required to use decorators for routes
routes = web.RouteTableDef()
# The youtube API sends a get request for the initial authorization
@routes.get('/')
async def authenticate(request):
if 'hub.challenge' not in request.query:
return web.Response(status=400)
print("Authenticated")
challenge_response = request.query.get('hub.challenge')
return web.Response(text=challenge_response, status=200)
# The youtube API sends post requests when new videos are posted
@routes.post('/')
async def receive(request):
# Ensure the post is of the proper type
content_type = request.content_type
if content_type != 'application/atom+xml':
return web.Response(status=400)
# Read all the data in the body and convert it to a dict
body_content = await request.content.read(n=-1)
data = xmltodict.parse(body_content, 'UTF-8')
# Ensure this is a proper video and its not already been announced before
if 'entry' in data['feed'] and data['feed']['entry']['yt:videoId'] not in self.memory:
entry = data['feed']['entry']
# Add video id to memory to prevent duplicates
self.memory.add(entry['yt:videoId'])
# store wanted data in a simple dict
video_data = {
'title': entry['title'],
'video_url': entry['link']['@href'],
'channel_name': entry['author']['name'],
'channel_url': entry['author']['uri'],
'date_published': entry['published'],
'video_id': entry['yt:videoId']
}
# Trigger the new_video event with video data
self.bot.dispatch('new_video', video_data)
return web.Response(status=200)
# Create application and connect the routes
app = web.Application()
app.add_routes(routes)
# Prepare the app runner
runner = web.AppRunner(app)
await runner.setup()
# Prepare the website
self.site = web.TCPSite(runner, '127.0.0.1', 8080)
# Wait until the discord bot is fully started
await self.bot.wait_until_ready()
# Start the web server
await self.site.start()
# Send subscribe request to API
await self.subscribe()
# Function to subscribe to the website
async def subscribe(self):
# Start web client to send post request
async with ClientSession() as session:
# Grab the ID from the channel url
channel_id = self.bot.config["target_channel"].split('/')[-1]
# Prepare the form data required to subscribe
payload = {
'hub.callback': self.bot.config['callback_url'],
'hub.mode': 'subscribe',
'hub.topic': f'https://www.youtube.com/xml/feeds/videos.xml?channel_id={channel_id}',
'hub.lease_seconds': '', # Might want to define this, max 828000 seconds
'hub.secret': '',
'hub.verify': 'async',
'hub.verify_token': ''
}
# Send post request to the API
async with session.post('https://pubsubhubbub.appspot.com/subscribe', data=payload) as response:
# if status is 202 it worked
if response.status == 202:
print("Subscribe request sent")
else:
print("Failed to subscribe")

- 11
- 1
-
Thank you so much! I have been searching for hours, liked and subbed your tutorial :D – ferrouskid Mar 09 '23 at 18:57