장거리 운전할 때 두시탈출 컬투쇼 들으면 졸음예방도 되고 지루하지 않아서 좋습니다. 라디오가 항상 잘 나온다는 보장도 없고 오후 2시~4시에만 컬투쇼를 들을 수 있기에 저는 우분투 기반의 홈서버를 활용하여 매일 컬투쇼를 예약 녹음하고 있습니다.


우선 다음과 같이 필요한 패키지를 설치합니다.


$ sudo apt-get install mimms

$ sudo apt-get install mplayer

$ sudo apt-get install lame 


SBS 라디오를 녹음하기 위한 스크립트를 생성합니다. 다음 내용을 rec_knn_radio.sh로 저장해 주세요.


#!/bin/bash

RADIO_ADDR="mms://211.220.195.199/viewradio"

RADIO_NAME="knn_radio"


PROGRAM_NAME=$1

RECORD_MINS=$2

DEST_DIR=$3

NO=$4


REC_DATE=`date +%Y%m%d`

TEMP_ASX=`mktemp -u`

TEMP_WAV=`mktemp -u`

MP3_FILE_NAME=$PROGRAM_NAME"_"$REC_DATE"_"$NO.mp3


ID3_TITLE=$PROGRAM_NAME"_"$REC_DATE"_"$NO

ID3_ARTIST=$RADIO_NAME

ID3_ALBUM=$PROGRAM_NAME

ID3_YEAR=`date +%Y`


mimms -t $RECORD_MINS $RADIO_ADDR $TEMP_ASX

mplayer -ao pcm:file=$TEMP_WAV $TEMP_ASX

lame --preset voice --tt $ID3_TITLE --ta $ID3_ARTIST --tl $ID3_ALBUM --ty $ID3_YEAR $TEMP_WAV $MP3                                       _FILE_NAME


rm $TEMP_WAV

rm $TEMP_ASX


mkdir -p $DEST_DIR

chgrp user $MP3_FILE_NAME

mv $MP3_FILE_NAME $DEST_DIR


SBS에서 고릴라 앱을 제공하면서 mms 서버를 막아놔서, KNN이 제공하는 mms를 활용하고 있습니다. 가끔은 컬투쇼가 아닌 다른 방송이 녹음되기도 합니다.


스크립트 파일에 실행 권한을 부여합니다.


$ chmod a+x recEbsRadio.sh


crontab에 다음과 같이 등록합니다.


# m h  dom mon dow   command

00 14 * * * /home/reshout/bin/rec_knn_radio.sh sbs_cultwo_show 60 /data/media/라디오 1 > /dev/null 2>&1

00 15 * * * /home/reshout/bin/rec_knn_radio.sh sbs_cultwo_show 60 /data/media/라디오 2 > /dev/null 2>&1


다음과 같은 형식의 이름으로 저장됩니다.


/data/media/라디오/sbs_cultwo_show_20121107_1.mp3

/data/media/라디오/sbs_cultwo_show_20121107_2.mp3


원인은 잘 모르겠지만 2시간 분량을 한번에 녹음할 수 없어서, 1시간씩 2번에 걸쳐 녹음하도록 설정했습니다.


조금 더 자세한 설명이 필요하시면 제가 예전에 작성한 글을 참조하세요.

http://blog.reshout.com/2692460


1. ffmpeg이 포함된 패키지 설치

sudo apt-get install libav-tools

2. 코덱 라이브러리 설치
sudo apt-get install libavcodec-extra-53

3. ffmpeg 실행, 출력파일 이름(무한도전.mp4)의 확장자(mp4)에 따라 container format이 결정됩니다.
ffmpeg -i 무한도전.avi -vcodec libx264 -acodec aac -strict experimental -ab 128k -ac 2 -b:v 640k -threads 2 -partitions 0 -flags +loop -cmp +chroma -subq 1 -trellis 0 -refs 1 -coder 0 -me_range 16 -g 300 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -maxrate 10M -bufsize 10M -qcomp 0.6 -qmin 2 -qmax 51 -qdiff 4 -level 30 무한도전.mp4


토렌트에서 받은 파일을 다운로드 디렉토리에서 원하는 곳으로 일일이 옮기는 것은 정말 귀찮은 작업입니다.


다음 파일의 다운로드가 완료되었을 때,


Mnet 슈퍼스타K4.6회.120921.720p.HDTV.H264-구제역돼지.mkv


다음 디렉토리로 이동하는 작업을,


/data/media/TV/슈퍼스타K4


자동화 하기 위해 간단한 node.js 모듈을 만들어 보았습니다.


이 모듈은 현재 홈서버에서 forever로 항시 동작하고 있습니다.


var fs = require('fs');

var path = require('path');


var torrentDir = '/data/torrent/';

var completeDir = path.join(torrentDir, 'complete');

var mediaDir = '/data/media/';

var tvDir = path.join(mediaDir, 'TV');


var workingFilename = {};

var dirMap = {};


dirMap[path.join(tvDir, '개그콘서트')] = /개그.*콘서트|개콘/;

dirMap[path.join(tvDir, '무한도전')] = /무한.*도전/;

dirMap[path.join(tvDir, '힐링캠프')] = /힐링.*캠프/;

dirMap[path.join(tvDir, '슈퍼스타K4')] = /슈퍼.*스타.*[kK].*4/;

dirMap[path.join(tvDir, '대왕의꿈')] = /대왕의.*꿈/;

dirMap[path.join(tvDir, '대풍수')] = /대풍수/;


fs.watch(completeDir, function(action, filename) {

  for (dir in dirMap) {

    var regExp = dirMap[dir];

    var targetDir = dir;


    if (regExp.test(filename)) {

      if (!workingFilename[filename]) {

        var fromPath = path.join(completeDir, filename);

        var toPath = path.join(targetDir, filename);


        workingFilename[filename] = toPath;

        setTimeout(function() {

          fs.rename(fromPath, toPath, function(err) {

            if (!err)

              console.log(filename + ': success');

            else

              console.log(filename + ': fail, ' + err);

            setTimeout(function() {

              delete workingFilename[filename];

            }, 5000);

          });

        }, 5000);

      }

      break;

    }

  }

});


이 모듈을 활용하시려면 Transmission이든 Deluge든 파일을 다운로드 중에 저장하는 디렉토리와 다운로드 완료 후 저장하는 디렉토리를 다르게 설정하셔야 합니다.


코드에 대해서 간단히 설명드리자면, 동일한 파일에 대하여 중복으로 fs.watch()가 callback을 불러주는 문제를 피하기 위하여 workingFilename이라는 map을 활용하고 있고, 파일이 생성되고 저장되고 옮겨지는 등의 시간차를 감안하여 setTimeout()을 적절히 활용하였습니다.


리눅스 서버를 위한 토렌트 클라이언트의 양대 산맥은 Transmission과 Deluge라고 할 수 있습니다.


Transmission이 가볍고 단순해서 좋긴 한데, 다운받은 파일의 user와 group이 debian-transmission이라 파일을 자동으로 관리하기가 영 불편해서, 최종적으로 Deluge를 선택하게 되었습니다. (Deluge는 deluged 프로세스의 user와 group을 지정할 수 있고, 자연스럽게 deluged가 다운받은 파일의 user와 group도 그대로 따라갑니다.)


Deluge는 비교적 화려한 기능과 인터페이스를 제공하지만, Python으로 구현되어 있어 Transmission보다 비교적 메모리를 많이 사용하고 느립니다.


설치는 잘 정리되어 있는 다음 문서를 그대로 따라하시면 됩니다.


http://linuxplained.com/install-deluge-web-interface-on-ubuntu-1204/


add-apt-repository가 없으신 분은 python-software-properties 패키지를 설치해 주시면 되겠습니다.


sudo apt-get install python-software-properties


설치 및 실행이 완료되면 다음 주소로 webui에 접근할 수 있습니다.


http://localhost:8112/


토렌트 등록, 시작, 멈춤, 삭제, 설정 등 모든 작업이 webui에서 가능합니다.


기본적인 동작에는 아무런 문제가 없지만 특정 디렉토리에 토렌트 파일을 복사해 넣으면 자동으로 다운로드가 시작되는 기능이 한글 토렌트 파일명에 대하여 동작하지 않는 문제가 있습니다.


Preferences > Downloads > Folder > Autoadd .torrent files from > /data/torrent


이 문제를 해결하기 위해 /data/torrent에 한글 이름의 토렌트 파일이 추가되면 임의의 영문 이름으로 바꾸는 node.js 모듈을 작성하여 forever로 돌리고 있습니다.


var fs = require('fs');

var path = require('path');


var torrentDir = '/data/torrent/';

var workingFilename = {};


function randomString(len, charSet) {

  charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

  var randomString = '';

  for (var i = 0; i < len; i++) {

      var randomPoz = Math.floor(Math.random() * charSet.length);

      randomString += charSet.substring(randomPoz,randomPoz+1);

  }

  return randomString;

}


fs.watch(torrentDir, function(action, filename){

  var hangulRegexp = /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/;

  var ext = path.extname(filename);


  if (!workingFilename[filename] && ext == '.torrent' && hangulRegexp.test(filename)) {

    var fromPath = torrentDir + filename;

    var toPath = torrentDir + randomString(8) + '.torrent';


    workingFilename[filename] = toPath;

    setTimeout(function() {

      fs.rename(fromPath, toPath, function(err) {

        if (!err) console.log(filename + ': success'); else console.log(filename + ': fail');

        setTimeout(function() {

          delete workingFilename[filename];

        }, 2500);

      });

    }, 2500);

  }

});


Samba를 통해 해당 디렉토리에 토렌트 파일을 복사한 경우, 같은 파일에 대하여 callback이 여러번 호출되기 때문에 map을 사용하여 중복을 피했고, 파일이 생성되고 내용이 저장되기 이전에 이름을 바꾸어 버리는 문제를 피하기 위해 시간차를 두었습니다.


Deluge가 기본으로 제공하는 플러그인 중에 토렌트 파일이 추가되거나 다운로드가 완료되었을 때, 특정 스크립트를 자동으로 실행하는 기능을 제공하는 Execute라는 플러그인이 있습니다.


자세한 내용은 다음 문서를 참조하세요.


http://dev.deluge-torrent.org/wiki/Plugins/Execute


참고로 플러그인을 사용하도록 설정한 후 webui에서 스크립트를 추가하려고 하면 javascript 에러가 발생하는데, deluged를 다시 시작하면 잘 됩니다.


이 역시 한글 이름의 토렌트 파일의 경우 제대로 동작하지 않습니다.


이 문제를 해결하기 위해 다음 문서를 참조하여,


http://forum.deluge-torrent.org/viewtopic.php?f=9&t=40517


Execute 플러그인의 소스코드를 수정하였습니다.


sudo vi /usr/share/pyshared/deluge/plugins/Execute-1.2.egg/execute/core.py


빨간색 부분의 코드를 추가하시면 됩니다.


122         # Go through and execute all the commands

123         for command in self.config["commands"]:

124             if command[EXECUTE_EVENT] == event:

125                 command = os.path.expandvars(command[EXECUTE_COMMAND])

126                 command = os.path.expanduser(command)

127                 log.debug("[execute] running %s", command)

128                 if isinstance(torrent_name, unicode):

129                     torrent_name = torrent_name.encode('utf-8')

130                 d = getProcessOutputAndValue(command, (torrent_id, torrent_name, save_path), env=os.environ)

131                 d.addCallback(log_error, command)


deluged를 다시 시작하면 의도한대로 added, complete 이벤트에 등록해 둔 script가 실행 됩니다.


다운로드가 완료된 후에 해당 토렌트를 삭제하고 싶다면 다음과 같은 스크립트를 사용하시면 됩니다.


#!/bin/bash

date=`date +%Y%m%d`

time=`date +%H:%M:%S`


echo \($date $time\) $1 $2 $3 >> /data/torrent/log/complete.log

deluge-console rm $1


deluge-console 패키지도 설치해 주셔야 합니다.


deluge-console를 사용하면 console에서 다운로드 상태를 보거나 토렌트를 추가하고 삭제하는 작업이 console에서 가능합니다. 자세한 내용은 다음 문서를 참조하세요.


http://whatbox.ca/wiki/Deluge_Console_Documentation


LG넷하드 N1T1을 잘 쓰다가 용량도 부족하고, 이것저것 해보기에는 여러가지로 제약이 많아서 홈서버를 구축하게 되었습니다.


가장 큰 동기는 node.js 입니다. 공부하면서 개인적으로 유용한 서비스를 몇가지 만들어 보려고 합니다.


처음에는 성능에 조금 욕심을 부려 셀레론G를 고려했는데, dc to dc 100W 파워로 감당할 수 있을지 확신이 들지 않았습니다. 그리고 전기세도 무시할 수 없을 것 같아서 저전력 CPU를 찾기에 이릅니다. 결론적으로는 TDP가 18W 밖에 되지 않으면서 Intel Atom보다 약간 성능이 나은 AMD E-350을 선택하게 되었습니다. (돈이 아주 많다면 Intel Core i3-2100T를 선택하는 것이 최선입니다.)



총 비용은 38만원 정도입니다. 기존에 사용하던 NAS를 12만원에 판매하기로 하였으니 대략 26만원이 더 들었네요.


AMD E-350이 나온지 오래 되어서 그런지 처음 선택한 메인보드가 품절이라 주문하는데 애를 좀 먹었습니다.


이번에 저전력 홈서버를 조립하면서 처음 알았는데, 저전력 CPU는 보통 메인보드에 장착된 상태로 판매됩니다.


케이스로 i7-BOOK을 선택한 이유는 3.5인치 HDD를 2개까지 장착할 수 있는 모델이기 때문입니다. 그런데 실제로 조립해보니  3.5인치 HDD를 2개 장착하려면 공간이 부족해서 선 정리하기가 쉽지 않을 것 같습니다.


i7-BOOK가 그리 작은 케이스는 아니기 때문에 조립 과정은 무난했습니다.



메인보드가 들어갈 자리를 잡기 위해 케이블을 밖으로 뺀 상태입니다. 메인보드 메뉴얼을 펼쳐 각 케이블이 장착되어야 할 위치를 미리 파악해 두었습니다.



ASRock E350M1/USB3은 AMD E-350을 장착한 메인보드 중에 사양이 좋은 편입니다. eSATA 포트와 USB 3.0 포트를 제공합니다. 



HDD를 장착하지 않은 상태에서 일단 부팅이 잘 되는지 확인해 보았습니다. 그런데 케이스에 달린 팬 두개 중 하나가 불량이라 엄청난 소음이 발생하여 그냥 사용하지 않기로 결정했습니다. 이틀째 아무런 문제 없이 잘 동작하고 있고, 저전력 CPU를 사용하고 있으니 앞으로도 큰 탈은 없을 것 같습니다.



HDD를 장착하고 케이블 정리까지 마쳤습니다. 나중에 HDD를 추가할 것에 대비하여 HDD를 한쪽 끝에 장착하였는데, 반대쪽에 HDD를 하나 더 장착하기에는 케이블 뭉치 때문에 공간이 허락될지 잘 모르겠습니다. 2.5인치 HDD는 무난히 추가로 장착할 수 있을 것 같습니다.



조립을 완료하니 이런 모습입니다. 깔끔하죠?


BIOS를 적절히 설정한 후, 미리 준비한 USB로 우분투 리눅스 12.04 LTS 서버를 설치하였습니다.


파티션은 이렇게 잡았습니다.



마지막으로 홈서버를 도메인에 연결하기 위한 작업을 했습니다. 

1. 공유기 설정에서 홈서버에 IP를 할당하고 DMZ로 설정

2. DNSEver에서 DDNS 추가

3. DDNS 정보를 업데이트하는 스크립트 파일을 cron에 등록


기존에 사용하던 NAS와 비슷한 전력을 소모하면서도, 훨씬 나은 사양을 갖추고 있고, 리눅스로 할 수 있는 모든 것을 시도해 볼 수 있는 홈서버를 구축해 보았습니다. 리눅스에 어느정도 경험을 가지고 계신 분이라면 과감히 도전해 보시기를 권합니다. 궁금한 점이 있으시면 댓글 남겨 주세요. 제가 아는 범위에서 성심 성의껏 답변해 드리겠습니다.


그동안 LG넷하드 N1T1을 잘 써왔지만 용량도 부족하고, SSH를 뚫었지만 성능과 자유도가 떨어져서 홈서버 구축을 준비하고 있습니다.  (N1T1의 메모리는 128MB, ARM 계열의 CPU를 사용하고 있어 최신 소스코드를 빌드하는데 어려움이 있습니다.)


N1T1의 소비 전력은 44W 입니다. 이 수준을 맞추기 위해 선택할 수 있는 제품은 많지 않습니다. 저는 저전력 CPU 중에서 Intel Atom D525보다 약간 성능이 나은 AMD E-350을 선택하였습니다. AMD E-350의 TDP는 18W이며, 참고로 지금 제가 사용하고 있는 Intel Core i5 750의 TDP는 95W입니다.



  • AMD E-350은 라데온 HD 6310을 포함하고 있습니다.
  • 저전력 CPU는 메인보드에 장착된 상태로 판매됩니다.
  • 100W의 dc to dc 전원을 사용하기 때문에 소음이 없습니다.
  • i7-BOOK은 3.5 HDD를 2개까지 장착할 수 있습니다.
  • SSD를 사용한다면 저전력, 무소음 PC로도 괜찮을 것 같네요.


AMD E-350의 전력소비, 성능이 궁금하신 분은 다음 링크를 참조하세요.

http://blog.naver.com/PostView.nhn?blogId=vobavoba&logNo=80124902643&viewDate=&currentPage=1&listtype=0


케이스에 관심 있으신 분은 여기로...

http://lovenabi93.blog.me/162705044

$ sudo apt-get install build-essential libssl-dev make scons git-core

$ git clone git://github.com/ry/node.gitgit clone git://github.com/ry/node.git

$ cd node

$ ./configure --without-snapshot

$ vi deps/v8/SConstruct


다음과 같이 수정합니다.


80 'gcc': {

81      'all': {

82        'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS', '-march=armv5t'],

83        'CXXFLAGS': ['-fno-rtti', '-fno-exceptions'],

84      },


1081  'armeabi': {

1082    'values': ['hard', 'softfp', 'soft'],

1083    'default': 'soft',

1084    'help': 'generate calling conventiont according to selected ARM EABI variant'


$ make

$ make install

$ node

>


Reference: https://github.com/joyent/node/issues/2131#issuecomment-3208846

First


if [ "$WINDOW" != "" ]; then
    export PS1='\nS:$WINDOW \e[1;32m\u\e[0m@\e[1;31m\h\e[0m:\e[1;33m\w\e[0m\n\$ '
else
    export PS1='\n\e[1;32m\u\e[0m@\e[1;31m\h\e[0m:\e[1;33m\w\e[0m\n\$ '
fi

Second


DEFAULT="[37;40m"

PINK="[35;40m"

GREEN="[32;40m"

ORANGE="[33;40m"


hg_dirty() {

    hg status --no-color 2> /dev/null \

    | awk '$1 == "?" { unknown = 1 }

           $1 != "?" { changed = 1 }

           END {

             if (changed) printf "!"

             else if (unknown) printf "?"

           }'

}


hg_branch() {

    hg branch 2> /dev/null | \

        awk '{ printf "\033[37;0m on \033[35;40m" $1 }'

    hg bookmarks 2> /dev/null | \

        awk '/\*/ { printf "\033[37;0m at \033[33;40m" $2 }'

}


export PS1='\n\e${PINK}\u \e${DEFAULT}at \e${ORANGE}\h \e${DEFAULT}in \e${GREEN}\w $(hg_branch)\e${GREEN}$(hg_dirty) \e${DEFAULT}\n$ '





집에서 회사일 및 알고리즘, 프로그래밍 공부를 해볼 요량으로 오랜만에 리눅스를 설치해 보았다. iptime 무선 랜카드 G054U-A를 사용하는 환경이라 이를 리눅스에서 동작하게 하기 위해서는 엄청난 삽질이 뒤따를 것을 감안하고 Ubuntu 8.10을 설치했는데, 놀랍게도 아무런 설정없이 바로 무선랜 카드를 사용할 수 있었다!

더욱 놀라운 것은 파티셔닝을 하지 않고 윈도우 파티션 내부에 가상 파일시스템을 구축하여 우분투를 설치할 수 있게 되었다는 것! 단 이때는 파일 시스템의 성능이 다소 저하될 수 있으며 Hibernation 기능을 사용할 수 없다. 그러나 이와 같은 방식으로 설치하고 사용해본 결과 눈에 띌만한 성능의 저하는 느낄 수 없었다. 간단히 윈도우에서 uninstaller를 실행하는 것으로 깔끔히 리눅스를 제거할 수 있다는 점도 상당히 매력적이다.


Ubuntu studio 테마를 설치하고, 네이버에서 받은 나눔고딕을 사용하도록 설정하니 윈도우보다 더 보기좋은 UI가 완성되었다! 회사 컴퓨터에도 설치해볼 계획인데, 부디 듀얼모니터 설정도 별다른 삽질 없이 마법처럼 되었으면...
사용자 삽입 이미지

작업환경을 완전히 리눅스로 옮겼다. 윈도우 컴퓨터에서 Putty로 셀레론 컴퓨터에 접속해서 GCC를 컴파일 하며 작업하다 듀얼 코어 컴퓨터에 리눅스를 설치하고 직접 컴파일 하니 속도가 2배 가까이 향상 된 듯한 느낌을 준다. 게다가 우분투 7.10은 설정하고 사용하기가 정말 편리하다.

빨간색을 좋아하다 보니 입맛에 맞게 글꼴과 테마를 수정했다. 그럭저럭 마음에 드는 개발 환경을 마련하는데 성공! 출근해서 저녁먹을때까지는 리눅스 환경에서 업무에 집중하자!

1. 설치

apache2와 svn과 apache2에서 svn을 사용하기 위한 모듈을 각각 설치한다.

sudo apt-get install apache2
sudo apt-get install subversion
sudo apt-get install libapache2-svn

이제 프로젝트 저장소(Repository)를 생성한다. 여기서는 tbpcb라는 프로젝트의 저장소를 /home/svn/tbpcb에 생성하는 것을 기준으로 설명한다.

/home/svn# sudo svnadmin create tbpcb
/home/svn# sudo chmod -R g+sw tbpcb
/home/svn# sudo chown -R www-data:www-data tbpcb

svn의 설정파일을 다음과 같이 편집한다. 예제는 아이디와 비밀번호를 통해 인증을 받아야 svn에 접근할 수 있도록 한다.

sudo vi /etc/apache2/mods-available/dav_svn.conf

<Location /svn/tbpcb>
  DAV svn
  SVNPath /home/svn/tbpcb

  AuthType Basic
  AuthName "Subversion Repository"
  AuthUserFile
/etc/apache2/dav_svn.passwd
   
  Require valid-user
</Location>

dav_svn.conf 파일에서 지정한 인증파일(dav_svn.passwd)에 아이디와 비밀번호를 추가하기 위해 htpasswd2를 사용한다. 여기서는 reshout라는 유저의 아이디와 비밀번호를 dav_svn.passwd에 저장한다. 유저를 추가하고 싶다면 -n 옵션을 써서 출력되는 내용을 dav_svn.passwd에 추가해 주면 된다.

/etc/apache2# sudo htpasswd2 -c -m dav_svn.passwd reshout

2. 사용

svn 저장소에 프로젝트를 처음 올릴 때 (import)

svn import -m "Initial Import" src http://192.168.12.12/svn/tbpcb

svn 저장소에서 프로젝트를 처음 받아 올 때 (check out)

svn co http://192.168.12.12/svn/tbpcb src

작업한 내용을 저장소에 반영할 때 (commit)

svn ci

저장소의 변경사항을 내 작업 공간에 반영할 때 (update)

svn up

+ Recent posts