본문 바로가기
프로그래밍

JPOP 탑50 노래 메들리 자동 생성

by 기이한날개 2022. 2. 4.

요즘 영상편집이나 코딩 작업하면서 음악 메들리를 많이 듣는다.

유튜브에서 2~3시간 짜리 노래 모음집을 일일이 찾는 것도 귀찮고, 안좋아하는 노래가 껴있는 메들리가 많다.

그래서 이번 주 JPOP 탑50 노래들을 이은 파일을 자동으로 만들어주는 코드를 짜봤다.

어디까지나 저작권이 있는 노래이기 때문에 혼자 듣는 용도로만 사용하고, 유튜브에 따로 올리거나 이걸로 수익을 창출하지는 않을 생각이다.

 

[JPOP 탑50 노래 메들리 만들기]

걸린 시간: 5시간

난이도: 하

새로 사용한 라이브러리: pytube, moviepy

 

JPOP 노래 랭킹은 레코초쿠라는 사이트에서 받아왔다. 

NTT Docomo가 가지고 있는 회사지만 음원 쪽으로는 그렇게 유명한 사이트는 아니긴 하다. 하지만 나는 좋은 노래만 들으면 되기 때문에 어디 랭킹이든 크게 신경쓰지 않았고 다른 사이트들과는 달리 랭킹이 앨범별로 나와 있는게 아니고 노래별로 나와 있어서 스크래핑하기 편하다는 이점이 있었다.

https://recochoku.jp/genreranking/j-pop/weekly

 

最新「J-POP」週間ランキング|レコチョク

最新曲が多数ランクイン。デイリーランキングは毎日更新。流行曲・ヒット曲をチェック。邦楽・洋楽・J-POP・アニメ・ヒップホップ/R&B/レゲエ・ロック・ダンス/エレクトロニカ・K-POP・歌謡

recochoku.jp

 

코드의 원리는 간단하다. 

top50 함수에서 이번주 탑50 노래의 제목과 아티스트 이름을 받아오고

download music 함수에서 유튜브에 '아티스트+작가'를 검색한 후 가장 처음 나오는 영상을 저장

make_video 함수에서 원하는 이미지와 함께 음악 파일을 모두 합친다.

from distutils.log import info
from bs4 import BeautifulSoup
from selenium import webdriver
from pytube import YouTube 
import os
import urllib.request
from urllib.parse import quote
import re
from moviepy.editor import *

# put the path to chromedriver
def create_soup(url):
    driver = webdriver.Chrome('D:/pythonworkspace/chromedriver') 
    driver.get(url) 
    html = driver.page_source
    soup = BeautifulSoup(html, "html.parser")
    return soup

def top50(soup):
    res = list()
    l = soup.find("ul", attrs={'id':'rankingContents'})
    items = l.findChildren('div', recursive=False)
    for item in items:
        info = item.find('div', attrs={'class':'c-product-list__info'})
        title = info.find('div', attrs={'class':'c-product-list__title c-el'}).getText()
        artist = info.find('div', attrs={'class':'c-product-list__artist c-el'}).getText()
        description = info.find('div', attrs={'class':'c-product-list__tieup'})
        if description is not None:
            description = description.getText()
        res.append([title, artist, description])
    return res

def download_music(song_path):
    for i, item in enumerate(items):
        title = item[0]
        artist = item[1]
        url = "https://www.youtube.com/results?search_query="
        encoded_text = quote(f'{artist} {title}')
        url = url + encoded_text
        request = urllib.request.Request(url)
        html = urllib.request.urlopen(request)
        video_ids = re.findall(r"watch\?v=(\S{11})", html.read().decode())
        print(video_ids)

        url = "https://www.youtube.com/watch?v=" + video_ids[0]
        yt = YouTube(url)
        title = yt.title
        title = re.sub('[-=+,#/\?:^$.@*\"※~&%ㆍ!』\\‘|\(\)\[\]\<\>`\'…》]',' ', title)
        print(title)
        i = str(i).zfill(2)
        name = f"{i}_{title}"
        strs = yt.streams.get_audio_only()
        strs.download(output_path=song_path, filename=name)

# 영상 만들기
def make_video(song_path, image_path):
    dirlist = os.listdir(song_path)
    videoclip_list = list()
    for song in dirlist:
        videoclip_list.append(AudioFileClip(song_path+song))

    audio = concatenate_audioclips(videoclip_list)
    clip = ImageClip(image_path).set_duration(audio.duration)
    clip = clip.set_audio(audio)
    clip.write_videofile("medely.mp4", fps=1)


url = "https://recochoku.jp/genreranking/j-pop/weekly"
song_path = FOLDER_PATH
image_path = IMAGE_PATH

items = top50(create_soup(url))
download_music(song_path)
make_video(song_path, image_path)

3시간 반짜리 영상을 만드는데 1시간 조금 넘게 걸린다.

다운로드 자체는 금방 하는데 역시 영상을 합쳐서 새로 만드는게 오래걸리는 것 같다.

사진을 안넣고 오디오로만 mp3 파일로 만들면 조금 더 빨리 만들어지고 용량도 작아질 것 같다.

 

+2022.02.04

pytube가 잘 작동하지 않는다. 커뮤니티를 찾아보니 아마 유튜브 쪽에서 자바스크립트를 변경했을 가능성이 있는 것 같다. 이번주 노래도 받아보게 빨리 해결되면 좋겠다.