├── .gitignore ├── MANIFEST.in ├── README.rst ├── screenshots ├── button_player.jpg ├── button_player.png ├── button_player_.jpg └── button_player_.png ├── setup.py └── torrent_stream ├── __init__.py ├── api.py ├── default_settings.py ├── exceptions.py ├── helpers.py ├── locale └── ru │ └── LC_MESSAGES │ └── django.po ├── settings.py ├── static └── torrent_stream │ ├── ajax-loader.gif │ ├── button.js │ ├── play_icon.png │ └── play_icon_small.png ├── templates ├── request.xml └── torrent_stream │ ├── button.html │ └── player.html ├── templatetags ├── __init__.py └── torrent_stream.py ├── urls.py └── views.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *~ 3 | *.mo -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include torrent_stream/static * 2 | recursive-include torrent_stream/templates * 3 | recursive-include torrent_stream/templatetags * 4 | recursive-include torrent_stream/locale * 5 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | django-torrent-stream 2 | ===================== 3 | 4 | Wraps the Torrent Stream http://torrentstream.org/ 5 | 6 | Installation 7 | ------------- 8 | 9 | Install a `stable version `_:: 10 | 11 | pip install django-torrent-stream 12 | 13 | Or install an alpha version:: 14 | 15 | pip install -e git://github.com/adw0rd/django-torrent-stream.git#egg=torrent_stream 16 | 17 | 18 | Add to ``settings.py``:: 19 | 20 | INSTALLED_APPS = ( 21 | ... 22 | 'torrent_stream' 23 | ) 24 | 25 | TORRENT_STREAM_AFFILIATE_KEY = "" 26 | TORRENT_STREAM_ZONE_ID = 27 | 28 | # You can specify size of player 29 | TORRENT_STREAM_PLAYER = { 30 | 'width': '650px', 31 | 'height': '342px', 32 | } 33 | 34 | These ``KEY`` and ``ID`` you can get on a page http://acestream.net/affiliate/ 35 | 36 | Add to ``urls.py``:: 37 | 38 | urlpatterns += patterns( 39 | ... 40 | url(r'^ts/', include('torrent_stream.urls')) 41 | ) 42 | 43 | For inclusion the ``torrent_stream.views``. Remember, you can change the prefix ``r'ts/'`` on anything. 44 | 45 | Usage 46 | --------- 47 | 48 | For example, you have a model Torrent:: 49 | 50 | class Torrent(models.Model): 51 | name = models.CharField(max_length=300, blank=True) 52 | content = models.FileField(upload_to="torrents/torrents", blank=True) 53 | 54 | 55 | You can display the button, when clicked, will be available to the player:: 56 | 57 | {% load torrent_stream %} 58 | {% torrent_stream_button torrent.content %} 59 | 60 | Result: 61 | 62 | ---- 63 | 64 | .. image:: https://raw.github.com/adw0rd/django-torrent-stream/master/screenshots/button_player_.png 65 | :target: http://kinsburg.tv/en/films/5430-puteshestvie-na-lunu/ 66 | 67 | ---- 68 | 69 | Or you can display a player at once:: 70 | 71 | {% load torrent_stream %} 72 | {% torrent_stream_player torrent.content %} 73 | 74 | How to get CONTENT_ID 75 | ------------------------ 76 | 77 | Sometimes you need to get ``CONTENT_ID``, you can do so:: 78 | 79 | from app.models import Torrent 80 | from torrent_stream.helpers import get_content_id 81 | 82 | torrent_obj = Torrent.objects.get(pk=42) 83 | 84 | # Enough to transmit the content of the torrent file 85 | content_id = get_content_id(torrent_obj.content.read()) 86 | 87 | # Or you can also pass the name of the torrent, and the duration to display the data in the player 88 | content_id = get_content_id(torrent_obj.content.read(), torrent_obj.name, duration_in_seconds) 89 | -------------------------------------------------------------------------------- /screenshots/button_player.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adw0rd/django-torrent-stream/113b03bdfbeacb1c9bfe9703325be9ccf896d2c9/screenshots/button_player.jpg -------------------------------------------------------------------------------- /screenshots/button_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adw0rd/django-torrent-stream/113b03bdfbeacb1c9bfe9703325be9ccf896d2c9/screenshots/button_player.png -------------------------------------------------------------------------------- /screenshots/button_player_.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adw0rd/django-torrent-stream/113b03bdfbeacb1c9bfe9703325be9ccf896d2c9/screenshots/button_player_.jpg -------------------------------------------------------------------------------- /screenshots/button_player_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adw0rd/django-torrent-stream/113b03bdfbeacb1c9bfe9703325be9ccf896d2c9/screenshots/button_player_.png -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from torrent_stream import __version__ 3 | 4 | long_description = "" 5 | try: 6 | readme = open("README.rst") 7 | long_description = str(readme.read()) 8 | readme.close() 9 | except: 10 | pass 11 | 12 | setup( 13 | name='django-torrent-stream', 14 | version=__version__, 15 | description="Wraps the Torrent Stream http://torrentstream.org/", 16 | long_description=long_description, 17 | keywords='django, torrent, torrent stream', 18 | author='Mikhail Andreev', 19 | author_email='x11org@gmail.com', 20 | url='http://github.com/adw0rd/django-torrent-stream', 21 | license='BSD', 22 | packages=['torrent_stream', ], 23 | install_requires=['requests', ], 24 | zip_safe=False, 25 | include_package_data=True, 26 | classifiers=[ 27 | "Development Status :: 3 - Alpha", 28 | "Environment :: Web Environment", 29 | "Programming Language :: Python", 30 | "Framework :: Django", 31 | "License :: OSI Approved :: BSD License", 32 | "Topic :: Software Development :: Libraries :: Application Frameworks", 33 | "Topic :: Software Development :: Libraries :: Python Modules", 34 | ], 35 | ) 36 | -------------------------------------------------------------------------------- /torrent_stream/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.9.3" 2 | -------------------------------------------------------------------------------- /torrent_stream/api.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import os.path 3 | import requests 4 | 5 | from lxml import etree 6 | from django.template import Context, Template 7 | 8 | import default_settings 9 | import exceptions 10 | 11 | 12 | class TorrentStreamAPI(object): 13 | _content_id = None 14 | 15 | def __init__(self, affiliate_key, zone_id, xml_api_url=None): 16 | """ 17 | @param string affiliate_key - 18 | @param integer zone_id - 19 | @see http://acestream.net/affiliate/index.php 20 | """ 21 | self.affiliate_key = affiliate_key 22 | self.zone_id = zone_id 23 | self.xml_api_url = xml_api_url or default_settings.XML_API_URL 24 | 25 | def send_request(self, template_name, params): 26 | """Send XML request 27 | @param string template_name - Path to xml-template 28 | @param dict params - Context for xml-template 29 | @return string - Response in XML 30 | """ 31 | xml_template = open(os.path.join(os.path.dirname(__file__), template_name)).read() 32 | xml_content = Template(xml_template).render(Context(params)) 33 | response = requests.post(self.xml_api_url, xml_content) 34 | return response.content 35 | 36 | def get_content_id(self, torrent_data, content_name=None, duration=None): 37 | """ 38 | @param string torrent_data - Content of torrent file 39 | @param string content_name - Name of video, example "My home video" (optional) 40 | @param integer duration - Duration of video in seconds (optional) 41 | """ 42 | self.torrent_data = base64.encodestring(torrent_data) 43 | self.content_name = content_name 44 | self.duration = duration 45 | 46 | if not self._content_id: 47 | # Request for getting Content ID 48 | try: 49 | xml_result = self.send_request("templates/request.xml", params=vars(self)) 50 | except (Exception, ), e: 51 | raise exceptions.ServerFault(e.message) 52 | tree = etree.HTML(xml_result) 53 | statuses = tree.xpath('//response/status') 54 | if statuses: 55 | status = statuses[0] 56 | if status.text == 'accepted': 57 | self._content_id = tree.xpath('//response/id/text()')[0] 58 | else: 59 | error = "TorrentStream Error: {0} (Errcode: {1})".format(status.attrib.get('error'), status.attrib.get('errorcode')) 60 | raise exceptions.FailedResponse(error) 61 | return str(self._content_id) 62 | -------------------------------------------------------------------------------- /torrent_stream/default_settings.py: -------------------------------------------------------------------------------- 1 | AFFILIATE_KEY = "" # see http://acestream.net/affiliate/index.php#profile-page 2 | ZONE_ID = "" # ID of board, see http://acestream.net/affiliate/index.php#zone-page 3 | XML_API_URL = "http://torrentstream.net/api/xml" 4 | -------------------------------------------------------------------------------- /torrent_stream/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Custom exception for TorrentStream 3 | """ 4 | 5 | 6 | class FailedResponse(Exception): 7 | pass 8 | 9 | 10 | class ServerFault(Exception): 11 | pass 12 | -------------------------------------------------------------------------------- /torrent_stream/helpers.py: -------------------------------------------------------------------------------- 1 | from settings import ( 2 | TORRENT_STREAM_AFFILIATE_KEY, TORRENT_STREAM_ZONE_ID) 3 | from api import TorrentStreamAPI 4 | 5 | 6 | def get_content_id(torrent_data, content_name="", duration=""): 7 | """Return content id by torrent data 8 | @param string torrent_data - Content of torrent file 9 | @param string content_name - Name of video, example "My video" (optional) 10 | @param integer duration - Duration of video in seconds (optional) 11 | @return integer 12 | """ 13 | api = TorrentStreamAPI( 14 | TORRENT_STREAM_AFFILIATE_KEY, 15 | TORRENT_STREAM_ZONE_ID) 16 | content_id = api.get_content_id( 17 | torrent_data, content_name, duration) 18 | return content_id 19 | -------------------------------------------------------------------------------- /torrent_stream/locale/ru/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Report-Msgid-Bugs-To: \n" 4 | "POT-Creation-Date: 2012-04-10 18:21+0400\n" 5 | "Content-Type: text/plain; charset=UTF-8\n" 6 | 7 | msgid "Watch online" 8 | msgstr "Смотреть онлайн" 9 | 10 | msgid "Are you sure you want to close the player?" 11 | msgstr "Вы уверены что хотите закрыть плеер?" 12 | -------------------------------------------------------------------------------- /torrent_stream/settings.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | 3 | TORRENT_STREAM_ZONE_ID = settings.TORRENT_STREAM_ZONE_ID 4 | TORRENT_STREAM_AFFILIATE_KEY = settings.TORRENT_STREAM_AFFILIATE_KEY 5 | 6 | TORRENT_STREAM_PLAYER = { 7 | 'width': '650px', 8 | 'height': '342px', 9 | } 10 | TORRENT_STREAM_CACHE_PREFIX = 'torrent_stream_' 11 | 12 | if hasattr(settings, 'TORRENT_STREAM_PLAYER'): 13 | TORRENT_STREAM_PLAYER.update(settings.TORRENT_STREAM_PLAYER) 14 | 15 | if hasattr(settings, 'TORRENT_STREAM_CACHE_PREFIX'): 16 | TORRENT_STREAM_CACHE_PREFIX = settings.TORRENT_STREAM_CACHE_PREFIX 17 | -------------------------------------------------------------------------------- /torrent_stream/static/torrent_stream/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adw0rd/django-torrent-stream/113b03bdfbeacb1c9bfe9703325be9ccf896d2c9/torrent_stream/static/torrent_stream/ajax-loader.gif -------------------------------------------------------------------------------- /torrent_stream/static/torrent_stream/button.js: -------------------------------------------------------------------------------- 1 | var torrent_stream = { 2 | 'video_box_id': 'torrent_stream_video_box', 3 | 'get_browser_size': function () { 4 | // Output window width and height 5 | var browserWidth, browserHeight; 6 | if (typeof(window.innerWidth) == 'number') { 7 | browserWidth = window.innerWidth; 8 | browserHeight = window.innerHeight; 9 | } else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) { 10 | // IE 6+ in 'standards compliant mode' 11 | browserWidth = document.documentElement.clientWidth; 12 | browserHeight = document.documentElement.clientHeight; 13 | } 14 | return {'w': parseInt(browserWidth), 'h': parseInt(browserHeight)} 15 | }, 16 | 'create_video_box': function () { 17 | // Create a video-box for output online video 18 | var video_box = document.createElement('div'); 19 | video_box.id = torrent_stream['video_box_id']; 20 | var browser_size = torrent_stream['get_browser_size'](); 21 | var box_top = (browser_size['h'] / 2) - (torrent_stream_config['box_height'] / 2); 22 | var box_left = (browser_size['w'] / 2) - (torrent_stream_config['box_width'] / 2); 23 | video_box.style.cssText = 24 | 'display: none;' + 25 | 'text-align: center;' + 26 | 'position: fixed;' + 27 | 'top:' + box_top + 'px;' + 28 | 'left:' + box_left + 'px;' + 29 | 'width:' + torrent_stream_config['box_width'] + 'px;' + 30 | 'height:' + torrent_stream_config['box_height'] + 'px'; 31 | document.body.appendChild(video_box); 32 | }, 33 | 'attach_video_player_to_video_box': function () { 34 | // Click to "Watch online" and setup video-player to video-box 35 | var video_box = document.getElementById(torrent_stream['video_box_id']); 36 | video_box.style.display = 'block'; 37 | video_box.innerHTML = 'Loading...'; 38 | 39 | var script = document.createElement('script'); 40 | script.type = "text/javascript"; 41 | script.src = torrent_stream_config['torrent_stream_js']; 42 | script.async = true; 43 | document.documentElement.appendChild(script); 44 | script.onload = function() { 45 | tsplayer( 46 | torrent_stream['video_box_id'], 47 | {width: torrent_stream_config['box_width'], height: torrent_stream_config['box_height']} 48 | ); 49 | document.getElementsByClassName('ts-power')[0].onclick = torrent_stream['dettach_video_player_from_video_box']; 50 | }; 51 | return false; 52 | }, 53 | 'dettach_video_player_from_video_box': function () { 54 | // When we click to "Close", then to hide a video-box 55 | var video_box = document.getElementById(torrent_stream['video_box_id']); 56 | video_box.style.display = 'none'; 57 | video_box.innerHTML = ""; 58 | return false; 59 | } 60 | } 61 | 62 | if (!document.getElementById(torrent_stream['video_box_id'])) { 63 | // Once create a video-box 64 | torrent_stream['create_video_box'](); 65 | } 66 | 67 | document.getElementById(torrent_stream_config['transport_id']).onclick = 68 | torrent_stream['attach_video_player_to_video_box']; 69 | 70 | document.addEventListener('keypress', function(e) { 71 | if (e.keyCode == 27) { // ESC 72 | torrent_stream['dettach_video_player_from_video_box'](); 73 | } 74 | }); 75 | 76 | document.getElementById('torrent_stream_video_box').onclick = function() { 77 | window.CLICK_TO_TS_PLAYER = true; 78 | } 79 | 80 | document.onclick = function() { 81 | if (document.getElementsByClassName('ts-power').length && !window.CLICK_TO_TS_PLAYER) { 82 | if (confirm(torrent_stream_config['close_player_confirm'])) { 83 | torrent_stream['dettach_video_player_from_video_box'](); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /torrent_stream/static/torrent_stream/play_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adw0rd/django-torrent-stream/113b03bdfbeacb1c9bfe9703325be9ccf896d2c9/torrent_stream/static/torrent_stream/play_icon.png -------------------------------------------------------------------------------- /torrent_stream/static/torrent_stream/play_icon_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adw0rd/django-torrent-stream/113b03bdfbeacb1c9bfe9703325be9ccf896d2c9/torrent_stream/static/torrent_stream/play_icon_small.png -------------------------------------------------------------------------------- /torrent_stream/templates/request.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ torrent_data }} 4 | {{ content_name }} 5 | {{ duration }} 6 | -------------------------------------------------------------------------------- /torrent_stream/templates/torrent_stream/button.html: -------------------------------------------------------------------------------- 1 | {% load i18n static %} 2 | {% if torrent_content_hash %} 3 | {% with 'torrent_stream_button_'|add:torrent_content_hash as transport_id %} 4 | {% trans "Watch online" as watch_online_translated %} 5 | 6 | {{ watch_online_translated }} 9 | {{ watch_online_translated }} 10 | 11 |
12 | 22 | 23 | {% endwith %} 24 | {% endif %} 25 | -------------------------------------------------------------------------------- /torrent_stream/templates/torrent_stream/player.html: -------------------------------------------------------------------------------- 1 | {% if torrent_content_hash %} 2 | {% with 'torrent_stream_transport_'|add:torrent_content_hash as transport_id %} 3 |
4 | 22 | {% endwith %} 23 | {% endif %} 24 | -------------------------------------------------------------------------------- /torrent_stream/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adw0rd/django-torrent-stream/113b03bdfbeacb1c9bfe9703325be9ccf896d2c9/torrent_stream/templatetags/__init__.py -------------------------------------------------------------------------------- /torrent_stream/templatetags/torrent_stream.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | from django import template 4 | from django.core.cache import cache 5 | 6 | from ..settings import TORRENT_STREAM_PLAYER, TORRENT_STREAM_CACHE_PREFIX 7 | 8 | register = template.Library() 9 | 10 | 11 | def torrent_stream_player(torrent_file): 12 | """Common context for player/button templates 13 | """ 14 | torrent_content_hash = '' 15 | if hasattr(torrent_file, 'read'): 16 | torrent_content = torrent_file.read() 17 | torrent_content_hash = hashlib.md5(torrent_content).hexdigest() 18 | cache.set( 19 | TORRENT_STREAM_CACHE_PREFIX + torrent_content_hash, 20 | {'content': torrent_content}) 21 | return { 22 | 'torrent_content_hash': torrent_content_hash, 23 | 'TORRENT_STREAM_PLAYER': TORRENT_STREAM_PLAYER, 24 | } 25 | 26 | 27 | def torrent_stream_button(*args): 28 | return torrent_stream_player(*args) 29 | 30 | 31 | register.inclusion_tag('torrent_stream/player.html')(torrent_stream_player) 32 | register.inclusion_tag('torrent_stream/button.html')(torrent_stream_button) 33 | -------------------------------------------------------------------------------- /torrent_stream/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, url 2 | 3 | 4 | urlpatterns = patterns( 5 | 'torrent_stream.views', 6 | url(r'^assets/(\w{32}).js$', 'torrent_stream_js', name='torrent_stream_js'), 7 | ) 8 | -------------------------------------------------------------------------------- /torrent_stream/views.py: -------------------------------------------------------------------------------- 1 | import urllib 2 | 3 | from django.core.cache import cache 4 | from django.http import HttpResponse, Http404 5 | 6 | from torrent_stream import settings 7 | from torrent_stream.helpers import get_content_id 8 | from torrent_stream.exceptions import FailedResponse, ServerFault 9 | 10 | 11 | def torrent_stream_js(request, torrent_content_hash): 12 | cache_key = settings.TORRENT_STREAM_CACHE_PREFIX + torrent_content_hash 13 | torrent_stream = cache.get(cache_key) 14 | if not torrent_stream: 15 | raise Http404 16 | 17 | content_id = torrent_stream.get('content_id', None) 18 | if not content_id: 19 | torrent_content = torrent_stream.get('content', None) 20 | if torrent_content: 21 | try: 22 | torrent_stream['content_id'] = get_content_id(torrent_content) 23 | cache.set(cache_key, torrent_stream) 24 | except (FailedResponse, ServerFault): 25 | pass 26 | url = 'http://torrentstream.net/p/{0}'.format(torrent_stream['content_id']) 27 | return HttpResponse(urllib.urlopen(url).read(), content_type='text/javascript') 28 | --------------------------------------------------------------------------------