관련지식
node.js, javascript, atd, crontab, request, moment
이전에 만들었던 EBS 외국어 라디오 편성표 데이터를 이용하여 자동으로 녹음하는 기능을 만들어보겠습니다. 이번에는 준비가 좀 필요합니다.
- 라디오 녹음을 위한 shell script 준비
https://velvio.tistory.com/219 를 참고하여 녹음을 하는 shell을 하나 만드셔야 합니다. 블로그 내용은 Debian chroot 를 기준으로 되어있지만 docker 에 ubuntu 를 설치해서 사용해도 되고, 그냥 리눅스에서도 됩니다. 가장 중요한것은 ffmpeg 가 설치되어있어야 하는것입니다. - atd 설치
보통 crontab은 익숙하지만 atd는 생소하실수도 있겠습니다. crontab는 주기적으로 실행하는 스케쥴 관리라면, atd는 단 한번만 수행하는 예약 실행 개념입니다. 만약 설치가 안되신 분은 사용가능하도록 해두셔야 합니다.sudo apt-get install at
변수 정의
먼저 변수가 필요하겠죠. url
엔 EBS 편성표 데이터를 JSON으로 가공한 주소를 넣으면 됩니다. 각자의 환경에 맞게 입력하시면 되고, 혹시 제가 사용하는 URL이 필요하신 분은 연락주시면 알려드리겠습니다.
let url = ''; //EBS 편송표를 가공한 데이터URL
let record_program = ['EBS 착!붙는 중국어', '박나리 미카미의 문화탐방 여행 일본어']; //녹음하고 싶은 방송의 이름
let shell_path = '/root/radio_record/ebs_record.sh'; //EBS 녹음 스크립트
let map = [];
let now = new Date().getTime();
let yyyymmdd = moment(now).format('YYYYMMDD');
for(let i = 0; i < record_program.length; i++) {
let program = record_program[i];
map[program] = {};
}
record_program
에는 녹음하고 싶은 방송의 이름을 넣으면 됩니다. 이때의 방송명은 데이터에 있는 방송 이름과 완전히 동일해야 합니다. shell_path
는 ffmpeg를 이용하여 녹음하는 쉘 스크립트의 경로입니다. 제가 참고했던 블로그의 쉘스크립트를 조금 변형해서 사용하고 있기 때문에, 제가 쓰는 쉘 스크립트는 밑에서 별도로 공개하겠습니다.
변수 map
은 자료구조의 Hash와 같은 기능으로 사용할 예정입니다. 방송명이 key가 됩니다.
로직
먼저 JSON으로 가공된 EBS 편성표 데이터를 request
패키지로 조회합니다.
request.get(url, async function(err, resp, body) {
let schedule_list = JSON.parse(body);
for(let i = 0; i < schedule_list.length; i++) {
let program = schedule_list[i];
}
});
EBS 외국어 라디오는 하루에 2,3 번씩 동일한 방송을 틀어줍니다. 당연히 모든 방송을 녹음할 필요는 없겠죠. 현재 시간을 기준으로 가장 빠른 방송만 녹음할 것입니다.
//현재 시간 이후 방송중에서 녹음하고 싶은 방송인지 확인. 이미 가장 빠른시간 하나만 저장한다.
if(now < program.timestamp && map[program.title] && !map[program.title].timestamp) {
map[program.title] = program;
}
골라낸 방송을 linux 명령어로 실행하여 예약 실행되도록 할것입니다. 실행될 리눅스 명령어는 아래의 형태가 될 것입니다.
echo '녹음쉘스크립트 "방송제목 - 방송내용" 녹음길이' | at 시:분 년-월-일
let title = `${program.title} - ${yyyymmdd} ${program.part}`;
title = title.replace(/\//g, ',');
let atTime = moment(program.timestamp).format('HH:mm YYYY-MM-DD');
let cmd = `echo '${shell_path} "${title}" ${program.running}' | at ${atTime}`;
console.log(cmd);
let { stdout, stderr } = await exec(cmd);
if(stdout)
console.log(stdout);
if(stderr)
console.error(stderr);
만약 쉘스크립트의 파라미터가 저와 다르다면 파라미터에 맞춰서 위 소스를 수정하면 됩니다. 제 경우엔 아래와 같이 실행될것입니다.
echo '/root/radio_record/ebs_record.sh "EBS 착!붙는 중국어 - 20191001 2강 중국어 발음1-2" 1500' | at 20:00 2019-10-01
실행 확인
node schedule
로 실행한 후 at -l
또는 atq
명령어를 실행하여 등록된 작업이 있는지 확인합니다. 변수 record_program
에 지정한 방송 갯수만큼 등록되어야 합니다.
root@chinese:~# at -l
28 Tue Oct 1 17:00:00 2019 a root
29 Tue Oct 1 20:00:00 2019 a root
만약 등록되는 내역이 없다면 방송제목은 동일하게 입력했는지, 현재 시간 이후에 방송 예정이 있는지, 쉘 스크립트는 정상 실행되었는지 확인이 필요합니다.
정상 동작하는것을 확인했다면 crontab, 부팅쉘 등 원하시는곳에 등록해서 사용하시면 됩니다.
저는 월요일부터 토요일까지 아침 10시에 실행되도록 crontab에 등록하였습니다.
00 10 * * 1-6 node /root/radio_record/schedule >> /root/cron.log
최종소스
ebs_record.sh)
#!/bin/sh
PROGRAM_NAME=$1
RECORD_SECS=$2
RADIO_ADDR="rtsp://new_iradio.ebs.co.kr:554/iradio/iradiolive_m4a"
TEMP_PATH="/tmp/`date +%H%M%S%N`.m4a"
DEST_PATH="/chinese_record/$PROGRAM_NAME.m4a"
echo "run `date`" >> ~/record.log
ffmpeg -rtsp_transport tcp -i $RADIO_ADDR -t $RECORD_SECS -codec:a copy -vn -metadata title="$PROGRAM_NAME" -metadata date=`date +%F` $TEMP_PATH
mv "$TEMP_PATH" "$DEST_PATH"
schedule.sh)
const request = require('request');
const moment = require('moment');
const util = require('util');
const exec = util.promisify(require('child_process').exec);
let url = ''; //EBS 편송표를 가공한 데이터URL
let record_program = ['EBS 착!붙는 중국어', '박나리 미카미의 문화탐방 여행 일본어']; //녹음하고 싶은 방송의 이름
// let record_program = ['박나리 미카미의 문화탐방 여행 일본어']; //녹음하고 싶은 방송의 이름
let shell_path = '/root/radio_record/ebs_record.sh'; //EBS 녹음 스크립트
let map = [];
let now = new Date().getTime();
let yyyymmdd = moment(now).format('YYYYMMDD');
for(let i = 0; i < record_program.length; i++) {
let program = record_program[i];
map[program] = {};
}
request.get(url, async function(err, resp, body) {
let schedule_list = JSON.parse(body);
for(let i = 0; i < schedule_list.length; i++) {
let program = schedule_list[i];
//현재 시간 이후 방송중에서 녹음하고 싶은 방송인지 확인. 이미 가장 빠른시간 하나만 저장한다.
if(now < program.timestamp && map[program.title] && !map[program.title].timestamp) {
map[program.title] = program;
let title = `${program.title} - ${yyyymmdd} ${program.part}`;
title = title.replace(/\//g, ',');
let atTime = moment(program.timestamp).format('HH:mm YYYY-MM-DD');
let cmd = `echo '${shell_path} "${title}" ${program.running}' | at ${atTime}`;
console.log(cmd);
let { stdout, stderr } = await exec(cmd);
if(stdout)
console.log(stdout);
if(stderr)
console.error(stderr);
}
}
});
'node.js' 카테고리의 다른 글
[node.js] 인스타그램 사용을 위한 instagram-web-api2 패키지 써보기 (0) | 2019.10.21 |
---|---|
[node.js] json config 파일을 제어하는 패키지 써보기 (0) | 2019.10.18 |
[node.js] EBS 외국어 라디오 편성표 파싱하기 (0) | 2019.10.01 |
[node.js] 디렉토리 파일목록 이름순으로 정렬하기 (0) | 2019.09.18 |
[node.js] Clova Speech Synthesis (CSS) 사용하기 (0) | 2019.08.28 |