added logging
Browse files- pytube/__init__.py +3 -0
- pytube/__main__.py +5 -0
- pytube/cipher.py +4 -0
- pytube/logging.py +90 -0
- pytube/mixins.py +12 -0
pytube/__init__.py
CHANGED
|
@@ -15,6 +15,9 @@ __author__ = 'Nick Ficano'
|
|
| 15 |
__license__ = 'MIT License'
|
| 16 |
__copyright__ = 'Copyright 2017 Nick Ficano'
|
| 17 |
|
|
|
|
| 18 |
from pytube.query import StreamQuery
|
| 19 |
from pytube.streams import Stream
|
| 20 |
from pytube.__main__ import YouTube
|
|
|
|
|
|
|
|
|
| 15 |
__license__ = 'MIT License'
|
| 16 |
__copyright__ = 'Copyright 2017 Nick Ficano'
|
| 17 |
|
| 18 |
+
from pytube.logging import create_logger
|
| 19 |
from pytube.query import StreamQuery
|
| 20 |
from pytube.streams import Stream
|
| 21 |
from pytube.__main__ import YouTube
|
| 22 |
+
|
| 23 |
+
logger = create_logger()
|
pytube/__main__.py
CHANGED
|
@@ -7,6 +7,7 @@ This module implements the core developer interface for pytube.
|
|
| 7 |
|
| 8 |
"""
|
| 9 |
import json
|
|
|
|
| 10 |
|
| 11 |
from pytube import extract
|
| 12 |
from pytube import mixins
|
|
@@ -17,6 +18,9 @@ from pytube.helpers import apply_mixin
|
|
| 17 |
from pytube.helpers import memoize
|
| 18 |
|
| 19 |
|
|
|
|
|
|
|
|
|
|
| 20 |
class YouTube(object):
|
| 21 |
|
| 22 |
def __init__(
|
|
@@ -122,6 +126,7 @@ class YouTube(object):
|
|
| 122 |
instances of :class:`Stream <Stream>` for each media stream.
|
| 123 |
|
| 124 |
"""
|
|
|
|
| 125 |
streams = self.player_config['args'][fmt]
|
| 126 |
for stream in streams:
|
| 127 |
video = Stream(
|
|
|
|
| 7 |
|
| 8 |
"""
|
| 9 |
import json
|
| 10 |
+
import logging
|
| 11 |
|
| 12 |
from pytube import extract
|
| 13 |
from pytube import mixins
|
|
|
|
| 18 |
from pytube.helpers import memoize
|
| 19 |
|
| 20 |
|
| 21 |
+
logger = logging.getLogger(__name__)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
class YouTube(object):
|
| 25 |
|
| 26 |
def __init__(
|
|
|
|
| 126 |
instances of :class:`Stream <Stream>` for each media stream.
|
| 127 |
|
| 128 |
"""
|
| 129 |
+
logger.info('building Stream instances')
|
| 130 |
streams = self.player_config['args'][fmt]
|
| 131 |
for stream in streams:
|
| 132 |
video = Stream(
|
pytube/cipher.py
CHANGED
|
@@ -4,12 +4,16 @@ pytube.cipher
|
|
| 4 |
~~~~~~~~~~~~~
|
| 5 |
|
| 6 |
"""
|
|
|
|
| 7 |
import re
|
| 8 |
from itertools import chain
|
| 9 |
|
| 10 |
from pytube.helpers import memoize
|
| 11 |
|
| 12 |
|
|
|
|
|
|
|
|
|
|
| 13 |
def get_initial_function_name(js):
|
| 14 |
"""Extracts the name of the function responsible for computing the signature.
|
| 15 |
"""
|
|
|
|
| 4 |
~~~~~~~~~~~~~
|
| 5 |
|
| 6 |
"""
|
| 7 |
+
import logging
|
| 8 |
import re
|
| 9 |
from itertools import chain
|
| 10 |
|
| 11 |
from pytube.helpers import memoize
|
| 12 |
|
| 13 |
|
| 14 |
+
logger = logging.getLogger(__name__)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
def get_initial_function_name(js):
|
| 18 |
"""Extracts the name of the function responsible for computing the signature.
|
| 19 |
"""
|
pytube/logging.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
import datetime as dt
|
| 3 |
+
import json
|
| 4 |
+
import logging
|
| 5 |
+
from collections import OrderedDict
|
| 6 |
+
|
| 7 |
+
from pytube import __version__
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
KEPT_ATTRS = ('funcName', 'module',)
|
| 11 |
+
RESERVED_ATTRS = (
|
| 12 |
+
'args',
|
| 13 |
+
'created',
|
| 14 |
+
'exc_info',
|
| 15 |
+
'exc_text',
|
| 16 |
+
'filename',
|
| 17 |
+
'levelno',
|
| 18 |
+
'lineno',
|
| 19 |
+
'msecs',
|
| 20 |
+
'msg',
|
| 21 |
+
'name',
|
| 22 |
+
'pathname',
|
| 23 |
+
'process',
|
| 24 |
+
'processName',
|
| 25 |
+
'relativeCreated',
|
| 26 |
+
'stack_info',
|
| 27 |
+
'thread',
|
| 28 |
+
'threadName',
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
class JsonFormatter(logging.Formatter):
|
| 33 |
+
def __init__(self, *args, **kwargs):
|
| 34 |
+
logging.Formatter.__init__(self, *args, **kwargs)
|
| 35 |
+
self.json_encoder = kwargs.get('json_encoder', self.json_encode)
|
| 36 |
+
self.kept_attrs = kwargs.get('kept_attrs', KEPT_ATTRS)
|
| 37 |
+
self.permanent_metadata = kwargs.get('metadata', {})
|
| 38 |
+
self.skipped_attrs = kwargs.get('skipped_attrs', RESERVED_ATTRS)
|
| 39 |
+
|
| 40 |
+
def extra_metadata(self):
|
| 41 |
+
return self.permanent_metadata
|
| 42 |
+
|
| 43 |
+
def get_timestamp(self):
|
| 44 |
+
return dt.datetime.utcnow().isoformat()
|
| 45 |
+
|
| 46 |
+
def json_encode(self, obj):
|
| 47 |
+
try:
|
| 48 |
+
if isinstance(obj, (bool, str, int, float, None,)):
|
| 49 |
+
return obj
|
| 50 |
+
except TypeError:
|
| 51 |
+
pass
|
| 52 |
+
|
| 53 |
+
return str(obj)
|
| 54 |
+
|
| 55 |
+
def jsonify(self, log):
|
| 56 |
+
return json.dumps(log, default=self.json_encoder, indent=2)
|
| 57 |
+
|
| 58 |
+
def format(self, record):
|
| 59 |
+
new_record = OrderedDict()
|
| 60 |
+
|
| 61 |
+
new_record['timestamp'] = self.get_timestamp()
|
| 62 |
+
new_record['message'] = record.getMessage()
|
| 63 |
+
new_record['levelname'] = record.__dict__.pop('levelname')
|
| 64 |
+
new_record['version'] = __version__
|
| 65 |
+
|
| 66 |
+
new_record.update(OrderedDict({'metadata': {'extra': {}}}))
|
| 67 |
+
# new_record['metadata'].update(self.extra_metadata())
|
| 68 |
+
|
| 69 |
+
for key, value in record.__dict__.items():
|
| 70 |
+
if key in self.kept_attrs:
|
| 71 |
+
new_record['metadata'][key] = value
|
| 72 |
+
elif key not in self.skipped_attrs:
|
| 73 |
+
new_record['metadata']['extra'][key] = value
|
| 74 |
+
|
| 75 |
+
if record.exc_info:
|
| 76 |
+
fmt_exception = self.formatException(record.exc_info)
|
| 77 |
+
new_record['metadata']['exception'] = fmt_exception
|
| 78 |
+
|
| 79 |
+
return '%s' % (self.jsonify(new_record))
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def create_logger():
|
| 83 |
+
logger = logging.getLogger()
|
| 84 |
+
|
| 85 |
+
handler = logging.StreamHandler()
|
| 86 |
+
handler.setFormatter(JsonFormatter())
|
| 87 |
+
|
| 88 |
+
logger.addHandler(handler)
|
| 89 |
+
logger.setLevel(logging.DEBUG)
|
| 90 |
+
return logger
|
pytube/mixins.py
CHANGED
|
@@ -4,11 +4,16 @@ pytube.mixins
|
|
| 4 |
~~~~~~~~~~~~~
|
| 5 |
|
| 6 |
"""
|
|
|
|
|
|
|
| 7 |
from pytube import cipher
|
| 8 |
from pytube.compat import parse_qsl
|
| 9 |
from pytube.compat import unquote
|
| 10 |
|
| 11 |
|
|
|
|
|
|
|
|
|
|
| 12 |
def apply_signature(video_info, fmt, js):
|
| 13 |
stream_map = video_info[fmt]
|
| 14 |
for i, stream in enumerate(stream_map):
|
|
@@ -16,6 +21,13 @@ def apply_signature(video_info, fmt, js):
|
|
| 16 |
if 'signature=' in url:
|
| 17 |
continue
|
| 18 |
signature = cipher.get_signature(js, stream['s'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
stream_map[i]['url'] = url + '&signature=' + signature
|
| 20 |
|
| 21 |
|
|
|
|
| 4 |
~~~~~~~~~~~~~
|
| 5 |
|
| 6 |
"""
|
| 7 |
+
import logging
|
| 8 |
+
|
| 9 |
from pytube import cipher
|
| 10 |
from pytube.compat import parse_qsl
|
| 11 |
from pytube.compat import unquote
|
| 12 |
|
| 13 |
|
| 14 |
+
logger = logging.getLogger(__name__)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
def apply_signature(video_info, fmt, js):
|
| 18 |
stream_map = video_info[fmt]
|
| 19 |
for i, stream in enumerate(stream_map):
|
|
|
|
| 21 |
if 'signature=' in url:
|
| 22 |
continue
|
| 23 |
signature = cipher.get_signature(js, stream['s'])
|
| 24 |
+
logger.debug(
|
| 25 |
+
'descrambling url signature %s ', stream['s'], extra={
|
| 26 |
+
's': stream['s'],
|
| 27 |
+
'signature': signature,
|
| 28 |
+
'itag': stream['itag'],
|
| 29 |
+
},
|
| 30 |
+
)
|
| 31 |
stream_map[i]['url'] = url + '&signature=' + signature
|
| 32 |
|
| 33 |
|