Producing stupid content on Youtube

On my daily journey down the Youtube rabbit hole at 2 a.m, I stumbled upon a series of videos with 2005esque TV news channel graphics and computer generated text-to-speech voiceovers. I linked the video but it really isn’t worth watching. I have no way to refund your 3 minutes if you did click on that link. In summary, the content is poorly produced and is probably just a text to speech program being run on a news article with stock graphics as a background. The video I stumbled upon didn’t really have too many views (goes to show how deep down the rabbit hole I really went) but that doesn’t mean this isn’t a big deal. These bots can churn out hundreds of videos per day. The quality of content isn’t even the biggest issue because we really can’t expect every Youtube channel to spend hours in production. Quality is meant to be a choice of the Youtube channel. The main issue is that these videos are very obviously plagiarizing content from other news websites. You can find hundreds of other bot driven channels that cover the exact same news content with slightly different backdrops. I also managed to find variations of TTS generated content such as this r/AskReddit based Youtube channel (I’m a bit conflicted on this one because some variations appear weirdly human but churn out enough content per day for me to suspect them).

The financial incentive

Apparently, NYTimes.com publishes on average 150 articles per day. In order to maximize Youtube ad revenue, the video would have to be around 10 minutes long. By a wordcounter.net estimation, a standard speaking pace would require around 1600 words for a 10-minute long speech. I’m not sure how many of the 150 articles are actually this long. Let’s assume that only the around 65 blog posts per day are usable content for the bot-generated videos. If you’ve ever uploaded a video to Youtube, you’d know that even a 10-second clip from a CCTV camera of a fly sitting on a wall would get around 4-6 views in the first 24 hours. Most of these views come from bots. These views don’t appear to be useful in terms of watch time analytics or ad revenue generation. The real money comes from real people (usually). According to most ad revenue calculators, assuming around 5 real human views per video and a pretty low engagement level of around 1%, your revenue would be around $3-5 per month. This is pretty paltry compared to what you could earn if you actually created useful content and encouraged engagement with your audience. However, these bots recognize their power in numbers. Large numbers.

If this bot were to run for a month,

  • Day 1: 65 videos, 5 views per video, 325 views for the day = $0.10 in ad revenue for the day
  • Day 2: 65 + 65 videos from the previous day, 5 views per video, 650 views for the day = $0.18 in ad revenue for the day
  • And so on

Obviously, the revenue won’t just scale up linearly. Videos will tend to gain fewer viewers over time. However, if everything went according to plan, these channels could be earning around $50 per month according to my napkin math. You might be thinking, $50 isn’t a whole lot of money for a month of plagiarizing.

The cost?

It costs literally nothing. It’s 50 free dollars for the first month and an increasing passive income for as long as Youtube decides to keep your video up. Your videos could earn even more if a couple of them went viral which is very possible if the news article happened to be controversial. $50 in your first month could easily turn into $500 over subsequent months. Also, there is nothing stopping these bots from being run on multiple channels and plagiarizing from more than 65 articles per day. $50 per month is as low as my estimate could get.

So I tried building my own bot…

My intention was never to plagiarize 65 articles per day and earn a passive income for myself. I just wanted to try writing a script to show how easy it is to generate content for Youtube. This isn’t particularly good content and it won’t earn any money because thankfully, Youtube has guidelines to prevent newly created channels from earning ad revenue. Also, I’m hesitant to call it a bot because I no longer run it on the cloud and it’s really just a Python script.

The first step of writing generating Youtube content is to find a source to plagiarize from. I found that Listverse has content that is formatted pretty much the same way in every article. “Top 10” videos also tend to be pretty popular so this might just end up being my new retirement plan.

BeautifulSoup is an awesome Python library for scraping the web! First, we need to open the URL of the blog post using the requests library and perform a GET request. We use headers to give us permission to perform the request since the website denies access from any non-user requests.

from bs4 import BeautifulSoup
import requests

url = "url"
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
page = requests.get(url, headers=headers)

I decided that the video would be formatted in the form of slides, just like any low-quality powerpoint presentation video. Each slide has a default duration of 3 seconds, an index, a title, and its content. Grouping chunks of content into slides made it easy to manipulate each group by calling functions on each object.

#slide class
class Slide:
    duration = 3
    def __init__(self, index, title, content):
        self.index = index
        self.title = title
        self.content = content

Next step is getting the relevant content from the page. I can’t show you the code for this because this implementation will vary based on which site you are scraping. But the idea is just to save all the useful details into Slide objects using the default constructor.

#creating slides
slides = []
#creating intro slide
intro_slide = Slide(0, title, preview)
#creating outro slide
outro_slide = Slide(11, "Thank you for watching!", "Please Like & Subscribe!")

slides.append(intro_slide)
for i in range(1, 11):
    slide = Slide(i, item_titles[i-1], item_contents[i-1])
    slides.append(slide)
slides.append(outro_slide)

These Slides are only abstract representations of what we need to put the video together. We need to generate images for each slide to have a visual representation of our content. I used PIL to generate images with text overlays for each slide. This was a little complicated as I needed to figure out how to scale each title and place it in the center of each image according to the total number of characters in the text. The textwrap library helps separate each block of text into multiple segments based on how many characters you want per line. Each image is saved in a directory called “video_name/images”. All the images are saved in this directory to later be accessed by an FFMPEG script and be concatenated into a video.

from PIL import Image, ImageDraw, ImageFont
import textwrap

#creating images for slides
font = ImageFont.truetype("arial.ttf", 60)

i = 0
for slide in slides:
    i = i+1
    if i == 1 or i == 12:
        img = Image.new('RGB', (632, 420), 'white')
    else:
        img = Image.new('RGB', (632, 420), (222,222,200))
    lines = textwrap.wrap(slide.title, width=20) #multi line title
    y_text = 80
    draw = ImageDraw.Draw(img)
    for line in lines:
        w, h = font.getsize(line)
        draw.text(((632 - w) / 2, y_text), line, font=font, fill="black")
        y_text += h     
    img.save("E:/youtube-generator/"+video_name+"/images/" + str(i) + ".jpg")

We’re almost done! We just need to generate speech using our text. I used the Google TTS library for Python. Since we’re generating audio files now, it is also convenient to update the duration of each slide from their default values. The duration of the slide is just the duration of the TTS audio file. I used mutagen to find the length of the MP3 file generated. All the audio files are stored in an audio subdirectory for easy use with FFMPEG.

from gtts import gTTS #text to speech
from mutagen.mp3 import MP3 #get audio durations

#generating audio files and durations
i = 0
for slide in slides:
    i = i + 1
    tts = gTTS(text=slide.content, lang='en')
    tts.save("E:/youtube-generator/"+video_name+"/audio/" + str(i) + ".mp3")
    #get durations here
    audio = MP3("E:/youtube-generator/"+video_name+"/audio/" + str(i) + ".mp3")
    slide.duration = audio.info.length

FFMPEG is our best option for programmatically generating videos. It is primarily used on the command line but you can also write C programs using the FFMPEG libraries. I decided to use a Batch script since I really didn’t want to mess with C. FFMPEG has an option to take a “blueprint” text file with references to the video clip names and concatenate them together. It has a similar option to concatenate audio files. Once we have the full-length video file and full-length audio file, we need to put these two together to generate the final video file. I generated the blueprint files in the Python script.

text_file = open(""+video_name+"/input.txt", "w")
audio_list = open(""+video_name+"/audio.txt", "w")
i = 0
for slide in slides:
    i = i + 1
    #write audio clips
    audio_list.write("file " + "'audio/" + str(i) + ".mp3'")
    audio_list.write("\n")
    #write video clips
    text_file.write("file " + "'images/" + str(i) + ".jpg'")
    text_file.write("\n")
    text_file.write("duration " + str(slide.duration))
    text_file.write("\n")
text_file.write("file " + "'images/" + str(12) + ".jpg'")        
text_file.close()

The blueprint needs to be formatted sort of like this:

file 'images/1.jpg'
duration 18.192
file 'images/2.jpg'
duration 75.768
file 'images/3.jpg'
duration 73.248
file 'images/4.jpg'
duration 81.432
file 'images/5.jpg'
duration 61.32
....
file 'images/11.jpg'
duration 68.592
file 'images/12.jpg'
duration 1.824
file 'images/12.jpg'

…and similarly for the audio files. Here are the three commands that make the magic happen!

ffmpeg -f concat -i input.txt -vsync vfr -pix_fmt yuv420p output.mp4 //concat images
ffmpeg -f concat -i audio.txt -c copy output.wav //concat audio
ffmpeg -i output.mp4 -i output.wav -c:v copy -c:a aac -strict experimental final.mp4 //put em together

The lesson to be learned

Here’s the stupid video I ended up generating.

Writing scripts to generate content isn’t a particularly new concept and it was never really difficult. I guess the whole point of this experiment was really just to show that there’s a lot of goofy things you can do with a little bit of free time and some Python. Don’t try this at home. Don’t steal content. There’s probably some legal way to use this script and earn money on Youtube. Perhaps you could use it to generate videos to supplement the growth of your Youtube channel while running a blog. The possibilities are endless (?)!

https://github.com/abhinavpola/youtube-generator