WebM transcoding added
authorRoman Bazalevsky <rvb@rvb.name>
Fri, 24 Jul 2015 11:26:44 +0000 (14:26 +0300)
committerRoman Bazalevsky <rvb@rvb.name>
Fri, 24 Jul 2015 11:26:44 +0000 (14:26 +0300)
Startup timeout added for upstart compatibility

README.md~ [deleted file]
plugins/m3u_plugin.py
plugins/torrenttv_api.py [new file with mode: 0644]
vlcclient/vlcclient.py
vlcclient/vlcmessages.py
vpconfig.py
vphttp.py

diff --git a/README.md~ b/README.md~
deleted file mode 100644 (file)
index 24b72df..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-AceProxy: Ace Stream HTTP Proxy
-===============================
-AceProxy allows you to watch [Ace Stream](http://acestream.org/) live streams or BitTorrent files over HTTP.
-It's written in Python + gevent and should work on both Linux and Windows (Mac OS should work too, but was not tested)
-
-Currently it supports Ace Stream Content-ID hashes (PIDs), .acestream files and usual torrent files.
-
-**For installation, configuration and using info, visit** [Wiki](https://github.com/ValdikSS/aceproxy/wiki)
index cc614f2ef130095c4349a12ff902f1dd12903274..2263dfe930007cbe2bcfe58fbf3121fba8362c98 100644 (file)
@@ -30,6 +30,8 @@ class M3u(VPProxyPlugin):
         
         if self.splitted_path[1]=='m3u':
           prefix='get'
         
         if self.splitted_path[1]=='m3u':
           prefix='get'
+        elif self.splitted_path[1]=='m3uw':
+          prefix='webm'  
         elif self.splitted_path[1]=='m3ut':
           prefix='mp4'  
         else:
         elif self.splitted_path[1]=='m3ut':
           prefix='mp4'  
         else:
diff --git a/plugins/torrenttv_api.py b/plugins/torrenttv_api.py
new file mode 100644 (file)
index 0000000..ce5a86d
--- /dev/null
@@ -0,0 +1,173 @@
+# coding=utf-8
+"""
+Torrent-TV API communication class
+Forms requests to API, checks result for errors and returns in desired form (lists or raw data)
+"""
+__author__ = 'miltador'
+
+import urllib2
+import socket
+import xml.dom.minidom as dom
+
+
+class TorrentTvApiException(Exception):
+    """
+    Exception from Torrent-TV API
+    """
+    pass
+
+
+class TorrentTvApi(object):
+    CATEGORIES = {
+        1: 'Детские',
+        2: 'Музыка',
+        3: 'Фильмы',
+        4: 'Спорт',
+        5: 'Общие',
+        6: 'Познавательные',
+        7: 'Новостные',
+        8: 'Развлекательные',
+        9: 'Для взрослых',
+        10: 'Мужские',
+        11: 'Региональные',
+        12: 'Религиозные'
+    }
+
+    @staticmethod
+    def auth(email, password, raw=False):
+        """
+        User authentication
+        Returns user session that can be used for API requests
+
+        :param email: user email string
+        :param password: user password string
+        :param raw: if True returns unprocessed data
+        :return: unique session string
+        """
+
+        xmlresult = TorrentTvApi._result(
+            'v2_auth.php?username=' + email + '&password=' + password + '&application=tsproxy')
+        if raw:
+            return xmlresult
+        res = TorrentTvApi._check(xmlresult)
+        session = res.getElementsByTagName('session')[0].firstChild.data
+        return session
+
+    @staticmethod
+    def translations(session, translation_type, raw=False):
+        """
+        Gets list of translations
+        Translations are basically TV channels
+
+        :param session: valid user session required
+        :param translation_type: playlist type, valid values: all|channel|moderation|translation|favourite
+        :param raw: if True returns unprocessed data
+        :return: translations list
+        """
+        xmlresult = TorrentTvApi._result(
+            'v2_alltranslation.php?session=' + session + '&type=' + translation_type)
+        if raw:
+            return xmlresult
+        res = TorrentTvApi._check(xmlresult)
+        translationslist = res.getElementsByTagName('channel')
+        return translationslist
+
+    @staticmethod
+    def records(session, channel_id, date, raw=False):
+        """
+        Gets list of available record for given channel and date
+
+        :param session: valid user session required
+        :param channel_id: id of channel in channel list
+        :param date: format %d-%m-%Y
+        :param raw: if True returns unprocessed data
+        :return: records list
+        """
+        xmlresult = TorrentTvApi._result(
+            'v2_arc_getrecords.php?session=' + session + '&channel_id=' + channel_id + '&date=' + date)
+        if raw:
+            return xmlresult
+        res = TorrentTvApi._check(xmlresult)
+        recordslist = res.getElementsByTagName('channel')
+        return recordslist
+
+    @staticmethod
+    def archive_channels(session, raw=False):
+        """
+        Gets the channels list for archive
+
+        :param session: valid user session required
+        :param raw: if True returns unprocessed data
+        :return: archive channels list
+        """
+        xmlresult = TorrentTvApi._result(
+            'v2_arc_getchannels.php?session=' + session)
+        if raw:
+            return xmlresult
+        res = TorrentTvApi._check(xmlresult)
+        archive_channelslist = res.getElementsByTagName('channel')
+        return archive_channelslist
+
+    @staticmethod
+    def stream_source(session, channel_id):
+        """
+        Gets the source for Ace Stream by channel id
+
+        :param session: valid user session required
+        :param channel_id: id of channel in translations list (see translations() method)
+        :return: type of stream and source
+        """
+        xmlresult = TorrentTvApi._result(
+            'v2_get_stream.php?session=' + session + '&channel_id=' + channel_id)
+        res = TorrentTvApi._check(xmlresult)
+        stream_type = res.getElementsByTagName('type')[0].firstChild.data
+        source = res.getElementsByTagName('source')[0].firstChild.data
+        return stream_type.encode('utf-8'), source.encode('utf-8')
+
+    @staticmethod
+    def archive_stream_source(session, record_id):
+        """
+        Gets stream source for archive record
+
+        :param session: valid user session required
+        :param record_id: id of record in records list (see records() method)
+        :return: type of stream and source
+        """
+        xmlresult = TorrentTvApi._result(
+            'v2_arc_getstream.php?session=' + session + '&record_id=' + record_id)
+        res = TorrentTvApi._check(xmlresult)
+        stream_type = res.getElementsByTagName('type')[0].firstChild.data
+        source = res.getElementsByTagName('source')[0].firstChild.data
+        return stream_type.encode('utf-8'), source.encode('utf-8')
+
+    @staticmethod
+    def _check(xmlresult):
+        """
+        Validates received API answer
+        Raises an exception if error detected
+
+        :param xmlresult: API answer to check
+        :return: minidom-parsed xmlresult
+        :raise: TorrentTvApiException
+        """
+        res = dom.parseString(xmlresult).documentElement
+        success = res.getElementsByTagName('success')[0].firstChild.data
+        if success == '0' or not success:
+            error = res.getElementsByTagName('error')[0].firstChild.data
+            raise TorrentTvApiException('API returned error: ' + error)
+        return res
+
+    @staticmethod
+    def _result(request):
+        """
+        Sends request to API and returns the result in form of string
+
+        :param request: API command string
+        :return: result of request to API
+        :raise: TorrentTvApiException
+        """
+        try:
+            result = urllib2.urlopen('http://api.torrent-tv.ru/' + request + '&typeresult=xml', timeout=10).read()
+            return result
+        except (urllib2.URLError, socket.timeout) as e:
+            raise TorrentTvApiException('Error happened while trying to access API: ' + repr(e))
\ No newline at end of file
index b2226997e7a2d38d4cfdb0b3b2bc45ebdc122ff9..048fd2ffe40d76bd96c7d29769fb43da465592af 100644 (file)
@@ -25,8 +25,8 @@ class VlcClient(object):
     '''
 
     def __init__(
     '''
 
     def __init__(
-        self, host='127.0.0.1', port=4212, password='admin', connect_timeout=5,
-            result_timeout=5, out_port=8081):
+        self, host='127.0.0.1', port=4212, password='admin', connect_timeout=10,
+            result_timeout=10, out_port=8081):
         # Receive buffer
         self._recvbuffer = None
         # Output port
         # Receive buffer
         self._recvbuffer = None
         # Output port
index da8606c1d3ac578d47b3ae22ba105d5a8187d42a..d2ebe45a375eb22ce8dc4e1ac17ad7bb665981a9 100644 (file)
@@ -13,6 +13,9 @@ class VlcMessage(object):
             command = 'new "' + stream_name + '" broadcast input "' + input + '" output ' + (pre_access + ':' if pre_access else '#')
             if qtype=='mp4':
                 command = command + 'transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128}:'
             command = 'new "' + stream_name + '" broadcast input "' + input + '" output ' + (pre_access + ':' if pre_access else '#')
             if qtype=='mp4':
                 command = command + 'transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128}:'
+            elif qtype=='webm':
+                command = command + 'transcode{vcodec=VP80,acodec=vorbis,vb=512,ab=64}:'
+                muxer='ffmpeg{mux=webm}'
             command = command +'http{mux=' + muxer + ',dst=:' + \
                 str(out_port) + '/' + stream_name + '} option sout-keep option sout-all enabled' + \
                 "\r\n" + 'control "' + stream_name + '" play'
             command = command +'http{mux=' + muxer + ',dst=:' + \
                 str(out_port) + '/' + stream_name + '} option sout-keep option sout-all enabled' + \
                 "\r\n" + 'control "' + stream_name + '" play'
index 05ecbbfa94ca23c899b7b976b1b62c72b31c193a..97d24fb1c5c99fb46d0ba7b42ec54d22ffbe8cb3 100644 (file)
@@ -8,7 +8,7 @@ import logging
 class VPConfig():
 
     # Message level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
 class VPConfig():
 
     # Message level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
-    debug = logging.DEBUG
+    debug = logging.INFO
     # HTTP Server host
     httphost = '0.0.0.0'
     # HTTP Server port
     # HTTP Server host
     httphost = '0.0.0.0'
     # HTTP Server port
@@ -30,7 +30,7 @@ class VPConfig():
     # Maximum concurrent connections (video clients)
     maxconns = 20
     # Logging to a file
     # Maximum concurrent connections (video clients)
     maxconns = 20
     # Logging to a file
-    loggingtoafile = False
+    loggingtoafile = True
     # Path for logs, default is current directory. For example '/tmp/'
     logpath = '/var/log/vpproxy/'
     #
     # Path for logs, default is current directory. For example '/tmp/'
     logpath = '/var/log/vpproxy/'
     #
@@ -38,9 +38,6 @@ class VPConfig():
     # VLC configuration
     # ----------------------------------------------------
     #
     # VLC configuration
     # ----------------------------------------------------
     #
-    vlcuse = True
-    # Spawn VLC automaticaly
-    vlcspawn = True
     # VLC cmd line (use `--file-logging --logfile=filepath` to write log)
     vlccmd = "vlc -I telnet --clock-jitter 0 --network-caching 500 --sout-mux-caching 2000 --telnet-password admin --telnet-port 4212"
     # VLC spawn timeout
     # VLC cmd line (use `--file-logging --logfile=filepath` to write log)
     vlccmd = "vlc -I telnet --clock-jitter 0 --network-caching 500 --sout-mux-caching 2000 --telnet-password admin --telnet-port 4212"
     # VLC spawn timeout
@@ -67,21 +64,6 @@ class VPConfig():
     vlcmux = 'ts'
     # Force ffmpeg INPUT demuxer in VLC. Sometimes can help.
     vlcforceffmpeg = False
     vlcmux = 'ts'
     # Force ffmpeg INPUT demuxer in VLC. Sometimes can help.
     vlcforceffmpeg = False
-    # Stream start delay for dumb players (in seconds)
-    # !!!
-    # PLEASE set this to 0 if you use VLC
-    # !!!
-    videodelay = 0
-    # Stream send delay after PAUSE/RESUME commands (works only if option
-    # above is enabled)
-    # !!!
-    # PLEASE set this to 0 if you use VLC
-    # !!!
-    videopausedelay = 0
-    # Seek back feature.
-    # Seeks stream back for specified amount of seconds.
-    # Set it to 30 or so.
-    videoseekback = 5
     # Delay before closing connection when client disconnects
     # In seconds.
     videodestroydelay = 5
     # Delay before closing connection when client disconnects
     # In seconds.
     videodestroydelay = 5
index 5237f21098a660841323c08a88e36fba00a5b883..6108bd81055d9b089e885c9e4380e4ffe331c6b9 100644 (file)
--- a/vphttp.py
+++ b/vphttp.py
@@ -9,8 +9,9 @@ import traceback
 import gevent
 import gevent.monkey
 # Monkeypatching and all the stuff
 import gevent
 import gevent.monkey
 # Monkeypatching and all the stuff
-
 gevent.monkey.patch_all()
 gevent.monkey.patch_all()
+# Startup delay for daemon restart
+gevent.sleep(5)
 import glob
 import os
 import signal
 import glob
 import os
 import signal
@@ -163,7 +164,7 @@ class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
             self.reqtype = self.splittedpath[1].lower()
             # If first parameter is 'pid' or 'torrent' or it should be handled
             # by plugin
             self.reqtype = self.splittedpath[1].lower()
             # If first parameter is 'pid' or 'torrent' or it should be handled
             # by plugin
-            if not (self.reqtype in ('get','mp4') or self.reqtype in VPStuff.pluginshandlers):
+            if not (self.reqtype in ('get','mp4','webm') or self.reqtype in VPStuff.pluginshandlers):
                 self.dieWithError(400)  # 400 Bad Request
                 return
         except IndexError:
                 self.dieWithError(400)  # 400 Bad Request
                 return
         except IndexError:
@@ -256,7 +257,7 @@ class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
                 else:
                     self.vlcprefix = ''
 
                 else:
                     self.vlcprefix = ''
 
-                logger.debug("Ready to start broadcast....")                    
+                logger.info("Starting broadcasting "+self.path)                    
                 VPStuff.vlcclient.startBroadcast(
                     self.vlcid, self.vlcprefix + self.path_unquoted, VPConfig.vlcmux, VPConfig.vlcpreaccess, self.reqtype)
                 # Sleep a bit, because sometimes VLC doesn't open port in
                 VPStuff.vlcclient.startBroadcast(
                     self.vlcid, self.vlcprefix + self.path_unquoted, VPConfig.vlcmux, VPConfig.vlcpreaccess, self.reqtype)
                 # Sleep a bit, because sometimes VLC doesn't open port in
@@ -317,10 +318,12 @@ class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
             self.dieWithError()
         finally:
             logger.debug("END REQUEST")
             self.dieWithError()
         finally:
             logger.debug("END REQUEST")
+            logger.info("Closed connection from " + self.clientip + " path " + self.path)
             VPStuff.clientcounter.delete(self.reqtype+'\\'+self.path_unquoted, self.clientip)
             if not VPStuff.clientcounter.get(self.reqtype+'\\'+self.path_unquoted):
                 try:
                     logger.debug("That was the last client, destroying VPClient")
             VPStuff.clientcounter.delete(self.reqtype+'\\'+self.path_unquoted, self.clientip)
             if not VPStuff.clientcounter.get(self.reqtype+'\\'+self.path_unquoted):
                 try:
                     logger.debug("That was the last client, destroying VPClient")
+                    logger.info("Stopping broadcasting " + self.path)
                     VPStuff.vlcclient.stopBroadcast(self.vlcid)
                 except:
                     pass
                     VPStuff.vlcclient.stopBroadcast(self.vlcid)
                 except:
                     pass