Telebot을 이용한 원격 토렌트 다운로드 시스템

취지

가족을 위해 원격 Torrent 다운로드 시스템을 만들기로 했다. 일반적으로 토렌트를 다운 받으려면 다음과 같은 일련의 과정이 필요하다.

  1. Torrent App을 다운 받고 실행한다. 필요하면 사용법을 익힌다.
  2. Torrent Site에 들어가 원하는 컨텐츠를 다운 받아 App으로 연다. Magnet주소이거나 Torrent File이거나 둘중에 하나다.
  3. Torrent App을 사용하여 다운로드한다.
  4. 컨텐츠를 원하는 곳에 복사한다. Google TV나 Phone.
  5. Player로 열기 위해 컨텐츠의 위치를 찾아가 Play 한다.

복잡하다. 그래서 이런 과정없이 간편히 Chat으로 Download 가능하도록 만들고자 했다.

그러기 위해 필요한 것은 아래 정도다.

  1. Telegram: 메신저 앱
  2. Raspberry pi2: 핵심적인 수행을 담당할 중앙 서버
  3. (Optional) Google TV: 컨텐츠를 플레이할 Android 기반 TV

설계도 (Block Diagram)

Telebot_Schemetics

Telegram

일단 원론적인 이야기부터 해보자. 2015년 6월 부터 TelegramBot API System을 도입했다. 간단히 설명하자면, 개발자가 만든 임의의Server와 통신하면서 Text, Image, Location 등을 주고 받을 수 있도록 해준다. 제공해주는 예제로는 Bot이 Text를 받고 적절한 그림을 보내준다거나 채팅 내용을 저장하는 정도가 있었다. Bot은 일반 User처럼 ID가 있고 누구나 그 ID와 대화를 시작하면 서비스를 이용할 수 있다. (물론 특정사용자만 이용토록 할 수도 있다.)

ad3f74094485fb97bd

더 재미있는 것은 이 Bot들을 위한 Open Market도 하나의 Bot으로 존재한다는 것이다.

Screenshot_20151220-163927

Telegram을 선택한 이유는 대부분의 Platform지원하고 개발이 쉽기 때문이다. 그리고 Bot API System이 이 프로젝트에 딱 적합해보였다. 실제로 Keyboard자리를 대체하는 GUI Button의 조합이 아주 유용했다.

Raspberry Pi 2

Raspberry Pi2는 Single Board Computer다. 손바다 보다 작은 크기지만 Linux가 돌아간다.

raspberry-pi.png
Rasberry pi2의 이전 제품인 Pi, 크기는 2와 같다.

그래서 이 프로젝트에서 서버 역할을 하기에 충분하다. 또 핸드폰 충전정도의 작은 전력만 소모하기 때문에 하루 종일 켜놓아도 부담없다.

이 작은 Board에서  명령어 처리뿐만 아니라 Torrent도 다운 받는다. 받아진 데이터는 꼳혀진 Micro SD Card에 저장된다. 그리고 FTP로 열어두면 어디서나 어느 장치에서도 접근 가능하다. 예를 들어 지하철에서 LTE폰으로 접근할 수 있다.

Google TV & PC

Google TV는 가정 내 공유기와 연결되어 있다. Raspberry pi2는 이야기했듯이 FTP Server로 열어두고 Google TV와 유선 연결된다. 물론 같은 Network상에 PC도 FTP를 통해 Raspberry pi2 Server에 접근할 수 있다.

20151220_170638.png

 

코드 설명

참고하실 분들을 위해 Github에 공유한다.

현재 코드는 개인적인 사정으로 2017-02-14 오후 8시부터 공개된다. : )
https://github.com/seungjuchoi/telegram-control-deluge

python으로 작성됐고 크게 3가지로 나눌 수 있다.

Blank Flowchart - New Page

  1. Chat
    Telebot에서 제공해주는 API를 사용하면 된다. 공식 사이트예제까지 아주 간단히 나와 있다. 이중에 실제로 사용한 Library는 python으로 만든 Telepot이다.

    Telepot: Python framework for Telegram Bot API.
    https://github.com/nickoala/telepotbot의 b를 위아래로 뒤집으면 p라는 점이 새삼 재밌어 보여서 선택했는데 꽤 편리한 Python API를 제공했다.Example을 보면 아래 단 세줄이 Telegram과 내 서버를 이어 주는 코드다.
    제목 없음
    MessageCounter는 실행할 Class자리리고 TOKEN은 Telegram에서 부여받은 BOT Key다.
  2. Torrent Search
    Torrent Search Site에 따라 알맞은 툴을 써야 한다. 처음에는 python web 분석 툴로 유명한 Beautiful Soup를 사용하려 했으나 막히는 부분이 있었다. 고민 끝에 Target이었던 Torrent site에서 검색 결과를 RSS로도 제공해준다는 것을 보고 그쪽으로 선회했다.Feedparser는 RSS를 Parsing하는 Tool로 자세한 방법은 여기를 참고하면 된다.
    Parsing은 아래 한줄이면 된다.
    ~~~~
    self.navi = feedparser.parse(대상 웹사이트)
    ~~~~
  3. Torrent Torrent Download
    리눅스 기반에 설치가능한 토렌트 시스템에는 여러 가지가 있다. 그중에 Transmission은 사용해봤기 때문에 Deluge를 사용해봤다. 비슷하지만 좀 더  Web과 App에서 상대적으로 유려한 UI를 제공해준다.
    Deluge-console을 apt에서 설치하면 Linux Shell에서 핵심적인 command를 수행할 수 있다.
    ~~~~
    $ deluge-console add <magnet>      – torrent 추가
    $ deluge-console info                          – 현재 상태정보
    $ deluge-console del <id>                  – torrent 삭제
    ~~~~

 

Screen Shot

Screenshot_20160103-082238
검색 요청
Screenshot_20160103-084112
토렌트 검색
Screenshot_20160103-084121
검색 후 리스트업
Screenshot_20160103-084125
선택

 

 

Telebot을 이용한 원격 토렌트 다운로드 시스템”에 대한 답글 28개

  1. token 의 valid_users 에는 무얼 적어야 하나요? 자꾸 Permission Denied 로 나옵니다.

    1. 답변이 늦어 죄송합니다.
      content_type, chat_type, chat_id = telepot.glance2(msg)
      위 코드에서 chat_id가 무엇인지 직접 print 해보시면 알 수 있습니다.
      사용자마다 고유한 값을 가지고있습니다.

      하지만 아무나 접근하지 못하도록한 조치일뿐이니 번거로우시다면 삭제하셔도 됩니다.
      물론 Bot Name을 알고 있다면 누구나 사용할 수 있게 됩니다.

  2. 안녕하세요 🙂
    저는 계속 from import 가 모두 문제가 생기는데요.
    urllib 이라던가 하는것들은 설치가 필요하지 않지않나요?ㅠㅠ
    초보라 멍청한 질문 죄송합니다.
    구글링으로 답을 찾지못해서요 ㅠㅠ

  3. 저는 검색까지는 구현했는데 계속 검색결과도 한개만 보여주고 다운이 link가 no attribute 라면서 오류가 납니다. 혹시 좀더 자세히 알 수 있을까요?

    좋은 선배님으로서 꼭 좀 부탁드리겠습니다 🙂 감사합니다!

    1. 안녕하세요. 저도 이 문제때문에 시간을 많이 허비했는데요. 답은 간단히 feedparser의 Document에 있습니다. 추측컨데 python3를 사용하실거고 python3에서 별다른 조치없이 feedparser를 사용하시면 그 에러가 발생합니다.

      해결방법은 이겁니다.

      아래 글은 Feedarser Manual이고
      요약하면, sgmllib.py 파일이 없으니 변환하거나 python2 lib에서 복사해서 python3 lib에 넣어라입니다.
      그럼 해결됩니다.

      If you’re using Python 3, feedparser will automatically be updated by the 2to3 tool; installation should be seamless across Python 2 and Python 3.

      There’s one caveat, however: sgmllib.py was deprecated in Python 2.6 and is no longer included in the Python 3 standard library. Because feedparser currently relies on sgmllib.py to handle illformed feeds (among other things), it’s a useful library to have installed.

      If your feedparser download included a copy of sgmllib.py, it’s probably called sgmllib3.py, and you can simply rename the file to sgmllib.py. It will not be automatically installed using the command above, so you will have to manually copy it to somewhere in your Python path.

      If a copy of sgmllib.py was not included in your feedparser download, you can grab a copy from the Python 2 standard library (preferably from the Python 2.7 series) and run the 2to3 tool on it:

      관련 링크: https://pypi.python.org/pypi/feedparser

  4. 안녕하세요 2달전부터 텔레그램으로 봇 만드신걸 보고 저도 시도해보려 했지만 밑에 에러가 계속 발생하는데 어디서 잘못된건지 감을 못잡겟네요 ㅠㅠ

    혹시 밑의 에러에 관해서 도움받을수 있을까요??

    telegrambot 실행후 봇에다가 msg를 보내면 저런 에러코드만 뜨고 봇이 응답이 없습니다.

    python3.5 telegram_torrenter.py
    Traceback (most recent call last):
    File “/usr/local/lib/python3.5/site-packages/telepot/__init__.py”, line 738, in collector
    callback(item)
    File “/usr/local/lib/python3.5/site-packages/telepot/__init__.py”, line 961, in handle
    d = make_delegate((self, msg, id))
    File “/usr/local/lib/python3.5/site-packages/telepot/delegate.py”, line 244, in f
    j = cls(seed_tuple, *args, **kwargs)
    File “telegram_torrenter.py”, line 108, in __init__
    super(Torrenter, self).__init__(seed_tuple, timeout)
    File “/usr/local/lib/python3.5/site-packages/telepot/helper.py”, line 894, in __init__
    super(ChatHandler, self).__init__(bot, seed, **kwargs)
    File “/usr/local/lib/python3.5/site-packages/telepot/helper.py”, line 660, in __init__
    super(ChatContext, self).__init__(bot, context_id, *args, **kwargs)
    File “/usr/local/lib/python3.5/site-packages/telepot/helper.py”, line 638, in __init__
    super(ListenerContext, self).__init__(*args, **kwargs)
    File “/usr/local/lib/python3.5/site-packages/telepot/helper.py”, line 852, in __init__
    super(DefaultRouterMixin, self).__init__(*args, **kwargs)
    TypeError: __init__() missing 1 required positional argument: ‘event_space’
    ^CTraceback (most recent call last):
    File “telegram_torrenter.py”, line 263, in
    bot.message_loop(run_forever=True)
    File “/usr/local/lib/python3.5/site-packages/telepot/__init__.py”, line 904, in message_loop
    time.sleep(10)
    KeyboardInterrupt

  5. 안녕하세요
    예전부터 클리앙에 남기셧던 글을 보고 블로그를 찾아와 비슷한 시스템을 시도해보려하는중인데 몇몇 에러들은 고쳣지만 밑의 에러들은 지금 한달째 어떻게 고쳐야할지 감이 안와서 여러 방면으로 시도했지만 성공을 하지 못했네요 ㅠㅠ

    밑의 에러들은 어떤식으로 접근해야 고칠수 있을까요??

    봇을 작동시키고 봇에게 메세지를 보내면 저런 에러들이 뜹니다.

    Traceback (most recent call last):
    File “/usr/local/lib/python3.5/site-packages/telepot/__init__.py”, line 738, in collector
    callback(item)
    File “/usr/local/lib/python3.5/site-packages/telepot/__init__.py”, line 961, in handle
    d = make_delegate((self, msg, id))
    File “/usr/local/lib/python3.5/site-packages/telepot/delegate.py”, line 244, in f
    j = cls(seed_tuple, *args, **kwargs)
    File “telegram_torrenter.py”, line 109, in __init__
    super(Torrenter, self).__init__(seed_tuple, timeout)
    File “/usr/local/lib/python3.5/site-packages/telepot/helper.py”, line 894, in __init__
    super(ChatHandler, self).__init__(bot, seed, **kwargs)
    File “/usr/local/lib/python3.5/site-packages/telepot/helper.py”, line 660, in __init__
    super(ChatContext, self).__init__(bot, context_id, *args, **kwargs)
    File “/usr/local/lib/python3.5/site-packages/telepot/helper.py”, line 638, in __init__
    super(ListenerContext, self).__init__(*args, **kwargs)
    File “/usr/local/lib/python3.5/site-packages/telepot/helper.py”, line 852, in __init__
    super(DefaultRouterMixin, self).__init__(*args, **kwargs)
    TypeError: __init__() missing 1 required positional argument: ‘event_space’
    ^CTraceback (most recent call last):
    File “telegram_torrenter.py”, line 264, in
    bot.message_loop(run_forever=True)
    File “/usr/local/lib/python3.5/site-packages/telepot/__init__.py”, line 904, in message_loop
    time.sleep(10)
    KeyboardInterrupt

    1. __init__() missing 1 required positional argument: ‘event_space’
      이부분으로 추측컨데
      Class _init_ 함수에 파라미터가 오류인것 같은 데 Telepot도 계속 업데이트 되고 있어서 최신버젼에선 기존 코드가 문제가 발생할 수 있어요. 그리고 전 python 3.4로 했구요.
      두달동안이나 하고 계시다니 코드를 좀 보여주시면 같이 찾아볼게요.

  6. 안녕하세요.. 이번에 라즈베리파이 하나 구매를 해서 열심히 삽질중인… 프로그래밍에 무지한 중생입니다.
    구글리을 하다다 이 블로그를 발견하게 되었구요.. 해당 소스를 다운바아 세팅바꾸고 실행을 했는데.. 아래 오류가 보입니다.

    ===============================================================================
    pi@raspberrypi:/usr/telegram-control-deluge-master $ python3 telegram_torrenter.py
    Traceback (most recent call last):
    File “/usr/local/lib/python3.4/dist-packages/telepot/__init__.py”, line 738, in collector
    callback(item)
    File “/usr/local/lib/python3.4/dist-packages/telepot/__init__.py”, line 961, in handle
    d = make_delegate((self, msg, id))
    File “/usr/local/lib/python3.4/dist-packages/telepot/delegate.py”, line 244, in f
    j = cls(seed_tuple, *args, **kwargs)
    File “telegram_torrenter.py”, line 108, in __init__
    super(Torrenter, self).__init__(seed_tuple, timeout)
    File “/usr/local/lib/python3.4/dist-packages/telepot/helper.py”, line 894, in __init__
    super(ChatHandler, self).__init__(bot, seed, **kwargs)
    File “/usr/local/lib/python3.4/dist-packages/telepot/helper.py”, line 660, in __init__
    super(ChatContext, self).__init__(bot, context_id, *args, **kwargs)
    File “/usr/local/lib/python3.4/dist-packages/telepot/helper.py”, line 638, in __init__
    super(ListenerContext, self).__init__(*args, **kwargs)
    File “/usr/local/lib/python3.4/dist-packages/telepot/helper.py”, line 852, in __init__
    super(DefaultRouterMixin, self).__init__(*args, **kwargs)
    TypeError: __init__() missing 1 required positional argument: ‘event_space’
    ===============================================================================

    실행을 해놓고,, 스마트폰에서 메시지를 보내면.. 이렇게 딱 오류가 보여지네요..

    일단 파이썬은 2.x 버전은 모두 삭제를 하고 python3을 설치를 하니 3.4버전 설치되었습니다.
    다른 feedparser, telepot도 인스톨을 다 했구요..

    그리고,. github에 있는 소스를 다운로드 받아서..
    특정 디렉토리에 풀고…
    setting.json 파일 내부를 수정했습니다. (제 bot token이랑 vaild_users는 제가 봇에세 메시지 던지고 난 후에 브라우저에서 확인 된 id 값을 넣었습니다)

    이렇게 하고.. telegram_torrenter.py를 실행을 했는데.. 위에처럼 나옵니다.

    블로그 댓글에 보면 저랑 같은 증상을 가지신 분이 보여서 답글을 읽었는데요.. 아이고.. 제가 영 무지해서.. 잘 모르겠네요. ㅎㅎㅎ

    혹시나 제가 잘못 처리 한 부분이 있을까요?

    그리고 해결 방법이 있을까요?

  7. telepot이 업데이트 되었나보네요 아래와 같이 수정하였더니 실행되었습니다.

    2d1
    < # -*- coding: utf-8 -*-
    10c9
    from telepot.delegate import per_chat_id, create_open
    30c29
    outString = ‘이름: ‘ + e[‘title’] + ‘\n’ + ‘상태: ‘ + e[‘status’] + ‘\n’
    108,109c107,108
    < def __init__(self, seed_tuple, **kwargs):
    def __init__(self, seed_tuple, timeout):
    > super(Torrenter, self).__init__(seed_tuple, timeout)
    208,210c207,209
    < # if not chat_id in VALID_USERS:
    < # print("Permission Denied")
    if not chat_id in VALID_USERS:
    > print(“Permission Denied”)
    > return
    244c243
    VALID_USERS = config[‘common’][‘valid_users’]
    262,263c261
    < pave_event_space()(
    (per_chat_id(), create_open(Torrenter, timeout=120)),

  8. 안녕하세요. 설명해주신대로 잘 설치하고 메시지 주고받는것까지는 잘되었습니다.

    질문이 있는데요..
    지금 사용하는 방법은 마그넷을 따와서 transmission rpc로 마그넷주소를 추가하여 다운받는것인지요?
    torrent파일을 다운받고 싶은데 어떻게해야 할지 감이오지 않습니다.

    저는 현재 라즈베리파이에 omv를 설치하고 omv의 플러그인으로 transmission을 설치한 상태라서
    잘 연동이 안되는것 같아요..

    위의 방법에서 torrent파일 (씨앗파일)을 watch폴더로 복사해버리면 될것같은데 어디부분을 수정하면 좋을까요..

    새해복많이 받으시고요 좋은방법 공유하여 주셔서 감사합니다.

    1. 안녕하세요.
      도움이 되셨다니 다행입니다.

      Torrent file download은 제가 crawling하는 site에서 지원하지 않습니다.(직접 사이트에 가시면 가능하시지만) Code를 보시면 아시겠지만 RSS로 읽어 Magnet만 가져오도록 되어 있습니다.
      사용하시는 OMV plugin에서 magnet을 제대로 load 할 수 있다면 문제없을 것 같습니다. 또 transmission 뿐만 아니라 deluge도 지원합니다. 그 부분은 deluge-console로 명령을 처리하는데 검색해보니 OMV plugin중 deluge를 위한 것도 있네요. transmission 연동에 문제가 계속 발생되시면 이 방법을 사용해보시는 것도 좋을 것 같습니다.

      또 질문 있으시면 말씀주세요. 좋은 하루되세요.
      감사합니다.

      1. 해결하여 피드백 남깁니다^^

        일단 저의 경우는 transmission-remote 명령어의 순서? 문법? 이라고 해야하나요..?
        이게 안맞아서 였습니다.

        그래서 transmission-remote 명령어를 구글링하니 사용예제가 있었습니다.
        (https://linux.die.net/man/1/transmission-remote)

        EX) : transmission-remote 라즈베리파이IP:PORT -option

        telegram_torrent.py 파일의
        108번째 줄
        cmd = ‘transmission-remote ‘ 를
        cmd = ‘transmission-remote 192.168.0.2:9091 ‘ 로 변경하니 잘되네요.

        즉, transmission-remote 192.168.0.2:9091 -n ID:PASS -l
        이렇게 해야 현재 토렌트 리스트를 가져오는 명령어였던거였습니다 ㅜ_ㅜ

        그리고 이미 토렌트 설정에서 포트와 저장위치는 설정이 되어있기 때문에 밑에있는
        124번째 줄
        os.system(self.transmissionCmd + pcmd + wcmd + ‘-a ‘ + magnet) 코드를
        os.system(self.transmissionCmd + ‘-a ‘ + magnet) 으로 변경하였습니다.

        코드를 깔끔하고 알아보기 쉽게 짜셔서 파악하기에 너무 좋았네요.^^

        다만 transmission의 문제인지 에러 메세지가 다깨져서 출력이되어서
        원인파악하는데 오래걸렸습니다.

        다른분들에게도 도움이 되었으면 좋겠네요.

        좋은방법 공유하여주시고 피드백 해주셔서 감사합니다.
        설날이 얼마 남지 않았네요. 또 한번 새해복 많이 받으시기 바랍니다.^^

      2. 피드백 감사합니다 : )
        새해 복많이 받으세요!

  9. 안녕하세요. 잘사용하고 있는 유저입니다.
    몇가지 질문이 있는데요.

    자막을 받을수 있는 방법은 없나요? 김씨네 rss에서 자막을 제공안해주니 어쩔수 없는 것인가요?

    1. 될겁니다. 작업이 필요할것 같은데 RSS말고 BS4를 활용해서 긁어오면 될 것 같은 느낌적인 느낌이네요. 🙂

  10. 안녕하세요. 한번 세팅해 보려고 어찌어찌 해보고 있는데요.
    import feedparser에서 에러가 발생합니다.

    도움을 부탁 드려도 될까요?

    Python 3.6.0 (default, Feb 17 2017, 20:18:36)
    [GCC 6.3.0] on linux
    Type “help”, “copyright”, “credits” or “license” for more information.
    >>> import feedparser
    Traceback (most recent call last):
    File “”, line 1, in
    File “/opt/lib/python3.6/site-packages/feedparser.py”, line 316
    raise KeyError, “object doesn’t have key ‘category'”
    ^
    SyntaxError: invalid syntax

    1. 네. 확인해볼게요. Feedpaser가 업데이트된거 아닌가 싶은데 :]

댓글 남기기