Skip to content

Commit

Permalink
Merge branch 'devel'
Browse files Browse the repository at this point in the history
  • Loading branch information
felipelerena committed Aug 24, 2014
2 parents 43b01f9 + 46fff6d commit d26b470
Show file tree
Hide file tree
Showing 11 changed files with 423 additions and 248 deletions.
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2
# -*- coding: utf-8 -*-

try:
Expand All @@ -13,7 +13,7 @@
version='0.5',
author='Felipe Lerena, Nicolás Demarchi',
description='A python app and library to watch series magically',
author_email='[email protected]',
author_email='[email protected] - [email protected]',
packages=['touchandgo'],
scripts=[],
url='http://github.com/touchandgo-devel/touchandgo/',
Expand Down
20 changes: 18 additions & 2 deletions touchandgo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
#! /usr/bin/env python
#! /usr/bin/env python2
import argparse
import logging
import sys

from time import time
from torrentmediasearcher import TorrentMediaSearcher
from libtorrent import version as libtorrent_version

from touchandgo.helpers import daemonize, set_config_dir
from touchandgo.history import History
from touchandgo.download import DownloadManager
from touchandgo.logger import log_set_up

log = logging.getLogger('touchandgo.main')


def watch(name, season=None, episode=None, sub_lang=None, serve=False,
quality=None, port=None):

def get_magnet(results):
print("Processing magnet link")
log.info("Processing magnet link")
magnet = results['magnet']
print(magnet)
log.info("Magnet: %s", magnet)
manager = DownloadManager(magnet, port=port, serve=serve,
sub_lang=sub_lang)
manager.start()
Expand All @@ -27,6 +34,7 @@ def get_magnet(results):
history.update()

print("Searching torrent")
log.info("Searching torrent")
search = TorrentMediaSearcher
if season is None and episode is None:
search.request_movie_magnet('torrentproject', name,
Expand All @@ -38,6 +46,7 @@ def get_magnet(results):
season=int(season), episode=int(episode),
quality=quality, callback=get_magnet)


def main():
parser = argparse.ArgumentParser()
parser.add_argument("name")
Expand All @@ -49,8 +58,15 @@ def main():
parser.add_argument("--daemon", action="store_true")
parser.add_argument("--port", "-p", default="8888")
parser.add_argument("--season", action="store_true")
parser.add_argument("--verbose", action="store_true", default=None)

args = parser.parse_args()

log_set_up(args.verbose)
log.info("Starting touchandgo")
log.info("Running Python %s on %r", sys.version_info, sys.platform)
log.info("Libtorrent version: %s", libtorrent_version)

if args.daemon:
daemonize(args, watch)
else:
Expand Down
4 changes: 2 additions & 2 deletions touchandgo/constants.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
STATES = ['queued', 'checking', 'downloading metadata', 'downloading',
'finished', 'seeding', 'allocating']
STATES = ['Queued', 'Checking', 'Downloading metadata', 'Downloading',
'Finished', 'Seeding', 'Allocating']
183 changes: 81 additions & 102 deletions touchandgo/download.py
Original file line number Diff line number Diff line change
@@ -1,85 +1,106 @@
from __future__ import division

import thread
import logging

from os import system, _exit
from os.path import join
from os.path import join, exists
from time import sleep
from datetime import datetime

from babelfish import Language
from guessit import guess_video_info
from libtorrent import add_magnet_uri, session
from subliminal import download_best_subtitles
from subliminal.subtitle import get_subtitle_path
from subliminal.video import Video
from libtorrent import add_magnet_uri, session, storage_mode_t

from touchandgo.constants import STATES
from touchandgo.helpers import is_port_free, get_free_port
from touchandgo.settings import DEBUG, TMP_DIR
from touchandgo.settings import DEBUG, TMP_DIR, DOWNLOAD_LIMIT, WAIT_FOR_IT, \
DEFAULT_PORT
from touchandgo.strategy import DefaultStrategy
from touchandgo.stream_server import serve_file
from touchandgo.subtitles import SubtitleDownloader


log = logging.getLogger('touchandgo.download')


class DownloadManager(object):
strategy_class = DefaultStrategy
sub_downloader_class = SubtitleDownloader

def __init__(self, magnet, port=None, sub_lang=None, serve=False):
self.magnet = magnet
if port is None:
port = 8888
port = DEFAULT_PORT
port = int(port)
if not is_port_free(port):
port = get_free_port()

log.info("[Magnet]: %s [Port]: %s [Sub_lang]: %s [Serve]: %s ",
magnet, port, sub_lang, serve)

self.port = port
self.sub_lang = sub_lang
self.serve = serve

# number of pieces to wait until start streaming
self.piece_st = 4
# we are waiting untill all the first peices are downloaded
self.holding_stream = True
# the biggest file which is supposed to be a video file
self._video_file = None
self.callback = serve_file
self._served_blocks = None
self.streaming = False

self.init_handle()
self.strategy = self.strategy_class(self)

if sub_lang is not None:
self.subtitle = self.sub_downloader_class(sub_lang)
else:
self.subtitle = None

def init_handle(self):
params = {
"save_path": TMP_DIR,
#"allocation": "compact"
"allocation": storage_mode_t.storage_mode_sparse,
}
self.session = session()
self.handle = add_magnet_uri(self.session, str(self.magnet), params)
self.handle.set_upload_limit(DOWNLOAD_LIMIT)

def start(self):
self.start_time = datetime.now()
print("Downloading metadata")
while not self.handle.has_metadata():
sleep(.1)
print("Starting download")
self.session.listen_on(6881, 6891)
self.session.start_dht()

chunks_strat = self.initial_strategy()

try:
self.start_time = datetime.now()
self.session.listen_on(6881, 6891)
self.session.start_dht()
print("Downloading metadata")
log.info("Downloading metadata")
while not self.handle.has_metadata():
print("\n" * 80)
self.stats()
sleep(.5)
log.info("Starting download")
self.strategy.initial()

while True:
if not self.handle.is_seed():
self.strategy_master(chunks_strat)
elif self.holding_stream:
self.holding_stream = False
self.stream_video()
self.strategy.master()
elif self.strategy.holding_stream:
self.strategy.holding_stream = False

if not self.streaming and self.handle.status().state == 3:
self.stream()

print("\n" * 80)
if DEBUG:
self.defrag()
self.stats()
sleep(1)
except KeyboardInterrupt:
_exit(0)
return

@property
def video_file(self):
if self._video_file is None:
self._video_file = self.get_biggest_file()

log.info("Video File: %s", self._video_file)
return self._video_file

def get_biggest_file(self):
Expand All @@ -93,92 +114,50 @@ def get_biggest_file(self):
return biggest_file

def run_vlc(self):
while not exists(join(TMP_DIR, self.video_file[0])):
sleep(WAIT_FOR_IT)
command = "vlc http://localhost:%s -q" % self.port
if self.sub_lang is not None:
subtitle = self.get_subtitle()
if self.subtitle is not None:
subtitle = self.subtitle.download(self.video_file)
if subtitle is not None:
command += " --sub-file %s" % subtitle
try:
system(command)
except KeyboardInterrupt:
pass
_exit(0)

def strategy_master(self, chunks_strat):
status = self.handle.status()
pieces = status.pieces
first_n = pieces[:self.piece_st]

if all(first_n):
self.handle.set_sequential_download(False)
pieces_strat = pieces[self.piece_st:self.piece_st + chunks_strat]
if self.holding_stream or all(pieces_strat):
if not self.holding_stream:
self.piece_st += chunks_strat
else:
if self.callback is not None:
self.stream_video()

for i in range(self.piece_st, self.piece_st + chunks_strat):
self.handle.piece_priority(i, 7)
self.handle.set_piece_deadline(i, 10000)

for i in range(self.piece_st+chunks_strat,
self.piece_st + chunks_strat*2):
self.handle.piece_priority(i, 5)
self.handle.set_piece_deadline(i, 20000)
self.holding_stream = False

def stream_video(self):
thread.start_new_thread(self.callback, (self, ))
if not self.serve:
thread.start_new_thread(self.run_vlc, ())
#try:
system(command)
#except KeyboardInterrupt:
# pass
#_exit(0)

def stream(self):
if self.callback is not None and not self.streaming:
self.streaming = True
status = self.handle.status()
pieces = status.pieces
self._served_blocks = [False for i in range(len(pieces))]
thread.start_new_thread(self.callback, (self, ))
if not self.serve:
thread.start_new_thread(self.run_vlc, ())

def block_served(self, block):
self._served_blocks[block] = True

def defrag(self):
status = self.handle.status()
numerales = ""
for i, piece in enumerate(status.pieces):
numeral = "#" if piece else " "
if self._served_blocks is not None and self._served_blocks[i]:
numeral = ">"
numeral += str(self.handle.piece_priority(i))
numerales += numeral
print(numerales)

def stats(self):
status = self.handle.status()
print '%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' % \
(status.progress * 100, status.download_rate / 1000,
status.upload_rate / 1000, status.num_peers, STATES[status.state])
print "Elapsed Time", datetime.now() - self.start_time

def initial_strategy(self):
self.handle.set_sequential_download(True)
status = self.handle.status()

for i in range(self.piece_st):
self.handle.piece_priority(i, 7)
self.handle.set_piece_deadline(i, 10000)

"""
last_piece = len(status.pieces) - 1
for i in range(last_piece-1, last_piece+1):
self.handle.piece_priority(i, 7)
self.handle.set_piece_deadline(i, 10000)
"""

return len(status.pieces) / 25

def get_subtitle(self):
print("Downloading subtitle")
video_file = self.video_file
filepath = join(TMP_DIR, video_file[0])
guess = guess_video_info(filepath, info=['filename'])
video = Video.fromguess(filepath, guess)
video.size = video_file[1]
subtitle = download_best_subtitles([video], {Language(self.sub_lang)},
single=True)
if not len(subtitle):
subtitle = None
else:
subtitle = get_subtitle_path(join(TMP_DIR, video.name))
return subtitle

def stats(self):
status = self.handle.status()
print '%s %.2f%% complete (down: %.1f kB/s up: %.1f kB/s peers: %d)' % \
(STATES[status.state], status.progress * 100,
status.download_rate / 1000, status.upload_rate / 1000,
status.num_peers)
print "Elapsed Time", datetime.now() - self.start_time
Loading

0 comments on commit d26b470

Please sign in to comment.