Weekend project: Build an automated YouTube Channel

You can't miss it. Today, the trend on YouTube is for static music videos with beautiful girls or landscapes. More often that not with the channel logo upfront.

I wanted to see if it was possible to create this kind of channel, fully automated with just a Python script.

The first step is to find a music source.

I wanted to find tracks not yet popular on YouTube but with a clear public interest.

I settled on the "Popular Now" playlist on Hype Machine. This was perfect as HypeMachine already as an API, so no need to go scrape the website.

Then, I needed elements to create the static image associated with the music.

For the background image, Unplash was the obvious choice. I created a collection of ~200 images that would fit for the videos. I would then only need to fetch a random one with https://source.unsplash.com/collection/<collectionid>/1920x1080.

I also needed my logo to be put on each video, so I made a quick one.

Here is what it would like at the end, after a quick merge:

Neat right?

I then created a folder for every channel I wanted to automate.
This allow me to easily add more channels, in less than 5 minutes.

creds.json contains the channel's oAuth token needed to upload videos to YouTube.

info.json is a very simple file containing some needed infos for the script:

{
    "name": "Chill Ocean","image": "https://source.unsplash.com/collection//1920x1080",
    "hypem": ["https://api.hypem.com/v2/popular?mode=now&count=10"]
}

Finally, res/titlelayer.png is the channel's logo to be merged.

Now the Python script.

I decided to use MoviePy to build the video, and youtube-upload to send it to YouTube.

{% highlight python %}

from termcolor import colored
from moviepy.editor import *
import json, requests, urllib, os, sys, os.path

reload(sys)
sys.setdefaultencoding("utf-8")

def createVideo(channel, image, title, artist, itemid, audio_url):

	uploaded_location = "/home/vince/Dropbox/Applications/"+channel+"/uploaded.txt"

	name = artist+' - '+title

    # Check in the synced text file if we already uploaded this song
    if itemid in open(uploaded_location).read():
        print name + colored(" -> Already uploaded", 'green')
        return
    else:
        print name + colored(" -> Let's upload", 'magenta')

    try:

        print 'Downloading audio...'
        urllib.urlretrieve(audio_url, 'temp_files/'+itemid+".mp3")

        print 'Downloading and merging images...'

        urllib.urlretrieve(image, "temp_files/image.jpg")

        audio = AudioFileClip("temp_files/"+itemid+".mp3")

        imageTitle = ImageClip(channel+'/res/titlelayer.png')
        background = ImageClip('temp_files/image.jpg').set_audio(audio)

        # Merge background and logo
        video = CompositeVideoClip([background, imageTitle]) 

        # Save a frame for thumbnail
        video.save_frame('temp_files/'+itemid+'.jpg') 

        # Export the video
        video.set_duration(audio.duration).write_videofile("temp_files/"+itemid+".mp4",fps=1) 

        # Remove the mp3
        os.system('rm temp_files/'+itemid+'.mp3')

        # Finally upload the video and remove it from disk when over
        yt_command = """youtube-upload 
            --credentials-file="""+channel+"""/creds.json 
            --title=\""""+name+"""\" 
            --description=\""""+title+" by "+artist+"""\" 
            --category=Music --tags='chill, electro, music' 
            --playlist 'Discover new sounds' 
            --thumbnail 'temp_files/"""+itemid+""".jpg' 
            temp_files/"""+itemid+""".mp4 """

        os.system(yt_command + "&& rm temp_files/"+itemid+".mp4 &")

        hs = open(uploaded_location,"a")
        hs.write(itemid+'\n')
        hs.close() 	

    except:
        print colored("An error happened, next.", 'red')

Get all channels sub-folders

for channel in [d for d in os.listdir('.') if os.path.isdir(os.path.join('.', d))]:
if channel == "temp_files": continue;

for channel in [d for d in os.listdir('.') if os.path.isdir(os.path.join('.', d))]:

	if channel == "temp_files": 
		continue;

    with open(channel+'/info.json') as data_file:    
        channelInfo = json.load(data_file)

    print '----------------------------------'
    print 'Treating channel '+colored(channelInfo['name'], 'blue')
    print '----------------------------------'

    for link in channelInfo['hypem']:

        # Parse tracks from the hypemachine links
        r = requests.get(link)
        tracks = json.loads(r.content)

        # For each tracks, create a video and upload it
        for track in tracks:
            createVideo(channel, 
                channelInfo['image'], 
                track['title'].encode('utf-8'), 
                track['artist'].encode('utf-8'), 
                track['itemid'], 
                'https://hypem.com/serve/public/'+track['itemid']
            )

colored("Script over.", 'red')

I wrote the id of the music to a file uploaded.txt  located on my Dropbox, so I could use the script on different computers without worrying that a music would be uploaded multiple times.

Then, you can either choose to manually run the script once a day or set up a cron job to do it for ya.

Final words

Unfortunately, after a while (6 months) YouTube disabled my channels after a copyright notice, without really explaining what video was the problem.

The first channel I published brought approximately 1000 subscribers and $1/day before it was shutdown, after a few months of full automation.

I would have posted my stats here but I can't access the dashboard anymore.

I'm now looking to start another channel with royalty-free music, to be free of copyright problems and take it as far as possible.

I can let you know when I write new posts