internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: ytdl-org/youtube-dl

Issue:
Reuse the instances of InfoExtractors in YoutubeDL
Currently, when it gets an url result with the `ie_key` set it creates a new instance of the extractor. Normally this is not bad, but if the extractor is YoutubeIE, it would need to be initialize again and if it have to login it'll waste time, since it's already done.

This happens for example when downloading the Youtube subscriptons feed, it could also happen if support for private playlists is added.

I think that instead of creating a new instance, we should reuse them.



Discussion:

Resolving patch:
diff --git a/youtube_dl/YoutubeDL.py b/youtube_dl/YoutubeDL.py
--- a/youtube_dl/YoutubeDL.py
+++ b/youtube_dl/YoutubeDL.py
@@ -97,6 +97,7 @@ class YoutubeDL(object):
     def __init__(self, params):
         """Create a FileDownloader object with the given options."""
         self._ies = []
+        self._ies_instances = {}
         self._pps = []
         self._progress_hooks = []
         self._download_retcode = 0
@@ -111,8 +112,21 @@ def __init__(self, params):
     def add_info_extractor(self, ie):
         """Add an InfoExtractor object to the end of the list."""
         self._ies.append(ie)
+        self._ies_instances[ie.ie_key()] = ie
         ie.set_downloader(self)
 
+    def get_info_extractor(self, ie_key):
+        """
+        Get an instance of an IE with name ie_key, it will try to get one from
+        the _ies list, if there's no instance it will create a new one and add
+        it to the extractor list.
+        """
+        ie = self._ies_instances.get(ie_key)
+        if ie is None:
+            ie = get_info_extractor(ie_key)()
+            self.add_info_extractor(ie)
+        return ie
+
     def add_default_info_extractors(self):
         """
         Add the InfoExtractors returned by gen_extractors to the end of the list
@@ -294,9 +308,7 @@ def extract_info(self, url, download=True, ie_key=None, extra_info={}):
          '''
         
         if ie_key:
-            ie = get_info_extractor(ie_key)()
-            ie.set_downloader(self)
-            ies = [ie]
+            ies = [self.get_info_extractor(ie_key)]
         else:
             ies = self._ies
 
diff --git a/youtube_dl/extractor/common.py b/youtube_dl/extractor/common.py
--- a/youtube_dl/extractor/common.py
+++ b/youtube_dl/extractor/common.py
@@ -106,6 +106,11 @@ def _real_extract(self, url):
         """Real extraction process. Redefine in subclasses."""
         pass
 
+    @classmethod
+    def ie_key(cls):
+        """A string for getting the InfoExtractor with get_info_extractor"""
+        return cls.__name__[:-2]
+
     @property
     def IE_NAME(self):
         return type(self).__name__[:-2]


Test patch:
Repository: ytdl-org/youtube-dl

Issue:
IE for criterion
test: http://www.criterion.com/films/712-3-women



Discussion:

Resolving patch:
diff --git a/youtube_dl/extractor/__init__.py b/youtube_dl/extractor/__init__.py
--- a/youtube_dl/extractor/__init__.py
+++ b/youtube_dl/extractor/__init__.py
@@ -8,6 +8,7 @@
 from .brightcove import BrightcoveIE
 from .collegehumor import CollegeHumorIE
 from .comedycentral import ComedyCentralIE
+from .criterion import CriterionIE
 from .cspan import CSpanIE
 from .dailymotion import DailymotionIE
 from .depositfiles import DepositFilesIE
diff --git a/youtube_dl/extractor/criterion.py b/youtube_dl/extractor/criterion.py
new file mode 100644
--- /dev/null
+++ b/youtube_dl/extractor/criterion.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from .common import InfoExtractor
+
+class CriterionIE(InfoExtractor):
+    _VALID_URL = r'http://www.criterion.com/films/(.*)'
+    _TEST = {
+        u'url': u'http://www.criterion.com/films/184-le-samourai',
+        u'file': u'184.mp4',
+        u'md5': u'bc51beba55685509883a9a7830919ec3',
+        u'info_dict': {
+            u"title": u"Le Samouraï",
+            u"description" : u"In a career-defining performance, Alain Delon plays a contract killer with samurai instincts. A razor-sharp cocktail of 1940s American gangster cinema and 1960s French pop culture, maverick director Jean-Pierre Melville&#x27;s masterpiece _Le Samouraï_ defines cool. "
+        }
+    }
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        video_id = mobj.group(1).split('-')[0]
+        webpage = self._download_webpage(url, video_id)
+
+        final_url = self._search_regex(r'so.addVariable\("videoURL", "(.+?)"\)\;',
+                                webpage, 'video url')
+        title = self._search_regex(r'<meta content="(.+?)" property="og:title" />',
+                                webpage, 'video title')
+        description = self._search_regex(r'<meta name="description" content="(.+?)" />',
+                                webpage, 'video description')
+        thumbnail = self._search_regex(r'so.addVariable\("thumbnailURL", "(.+?)"\)\;',
+                                webpage, 'thumbnail url')
+        ext = final_url.split('.')[-1]
+
+        return {'id': video_id,
+                'url' : final_url,
+                'title': title,
+                'ext': ext,
+                'description': description,
+                'thumbnail': thumbnail,
+                }


Test patch:
Repository: ytdl-org/youtube-dl

Issue:
Encrypted sig 87 broken again
All in title encrypted sig 87 are broken again.
Thanks.



Discussion:
new sig len 87 algo:

E911918ECB1C18AED66D42DD2B9D0FB1AEF8999E812.FE13EF2964BE256F8C6E3F6103F1DBE70C1FB5A8A66
8A5BF1C07EBD1F3016F3E6C8F652EB1692FE31EF.216E9998FEA1BF0D9B2DD24D66DEA81CEBCE8194

31B01B49DE02A8A630941CDA800A5CD632716018B13.FDDD384821F35B09D76C69E0F7492D1276B1808B8EE
B8081B6721D2947F0E96C67D90B53F028483DDDF.31E810617236DC5A008ADC149036A8A23ED94B11

python:
s[83:53:-1] + s[3] + s[52:40:-1] + s[86] + s[39:10:-1] + s[0] + s[9:3:-1] + s[53]

javascript:
s.slice(54, 84).reverse().join('') + s[3] + s.slice(41, 53).reverse().join('') + s[86] + s.slice(11, 40).reverse().join('') + s[0] +s.slice(4, 10).reverse().join('') + s[53]


Resolving patch:
diff --git a/youtube_dl/extractor/youtube.py b/youtube_dl/extractor/youtube.py
--- a/youtube_dl/extractor/youtube.py
+++ b/youtube_dl/extractor/youtube.py
@@ -338,7 +338,7 @@ def _decrypt_signature(self, s):
         elif len(s) == 88:
             return s[48] + s[81:67:-1] + s[82] + s[66:62:-1] + s[85] + s[61:48:-1] + s[67] + s[47:12:-1] + s[3] + s[11:3:-1] + s[2] + s[12]
         elif len(s) == 87:
-            return s[4:23] + s[86] + s[24:85]
+            return s[83:53:-1] + s[3] + s[52:40:-1] + s[86] + s[39:10:-1] + s[0] + s[9:3:-1] + s[53]
         elif len(s) == 86:
             return s[83:85] + s[26] + s[79:46:-1] + s[85] + s[45:36:-1] + s[30] + s[35:30:-1] + s[46] + s[29:26:-1] + s[82] + s[25:1:-1]
         elif len(s) == 85:


Test patch:
Repository: ytdl-org/youtube-dl

Issue:
Invalid signature again
Decryption function:

```
function kj(a) {
    a = a.split("");
    a = a.slice(2);
    var b = a[0];
    a[0] = a[18 % a.length];
    a[18] = b;
    a = a.slice(3);
    return a.join("")
};
```



Discussion:
new sig len 86 algo:

pairs:
1212C22C5559E88AC0F122A21EE1131083210F23DFCF2.A91FD047A924BCF260E0CBE351738E9C766C81D8
22C5559E88AC0F112A21EE1131083210F23DFCF2.A91FD047A924BCF260E0CBE351738E9C766C81D8

0808FC8F8601E908A2C3C1EF3137D99893C2C41236E7B.27BB47F10DB382EDD03C16C4FB186AAC42BA76D0
C8F8601E908A2C301EF3137D99893C2C41236E7B.27BB47F10DB382EDD03C16C4FB186AAC42BA76D0

python:
s[5:20] + s[2] + s[21:]

javascript:
s.slice(5, 20).join('') + s[2] + s.slice(21).join('')


Resolving patch:
diff --git a/youtube_dl/extractor/youtube.py b/youtube_dl/extractor/youtube.py
--- a/youtube_dl/extractor/youtube.py
+++ b/youtube_dl/extractor/youtube.py
@@ -340,7 +340,7 @@ def _decrypt_signature(self, s):
         elif len(s) == 87:
             return s[83:53:-1] + s[3] + s[52:40:-1] + s[86] + s[39:10:-1] + s[0] + s[9:3:-1] + s[53]
         elif len(s) == 86:
-            return s[83:85] + s[26] + s[79:46:-1] + s[85] + s[45:36:-1] + s[30] + s[35:30:-1] + s[46] + s[29:26:-1] + s[82] + s[25:1:-1]
+            return s[5:20] + s[2] + s[21:]
         elif len(s) == 85:
             return s[2:8] + s[0] + s[9:21] + s[65] + s[22:65] + s[84] + s[66:82] + s[21]
         elif len(s) == 84:


Test patch:
Repository: ytdl-org/youtube-dl

Issue:
IE for www.hark.com [audio]
audio
http://www.hark.com/clips/pxgfgqnpzn-stop-dave-im-afraid-full



Discussion:
It's easy I am on it. Hark has an iframe embedded on the page. The url of that iframe for the above clip is `http://www.hark.com/clips/pxgfgqnpzn/homepage_embed` If we request that embed page then we get the mp3 link which is present in that embed page.


Resolving patch:
diff --git a/youtube_dl/extractor/__init__.py b/youtube_dl/extractor/__init__.py
--- a/youtube_dl/extractor/__init__.py
+++ b/youtube_dl/extractor/__init__.py
@@ -29,6 +29,7 @@
 from .generic import GenericIE
 from .googleplus import GooglePlusIE
 from .googlesearch import GoogleSearchIE
+from .hark import HarkIE
 from .hotnewhiphop import HotNewHipHopIE
 from .howcast import HowcastIE
 from .hypem import HypemIE
diff --git a/youtube_dl/extractor/hark.py b/youtube_dl/extractor/hark.py
new file mode 100644
--- /dev/null
+++ b/youtube_dl/extractor/hark.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from .common import InfoExtractor
+from ..utils import determine_ext
+
+class HarkIE(InfoExtractor):
+    _VALID_URL = r'https?://www\.hark\.com/clips/(.+?)-.+'
+    _TEST = {
+        u'url': u'http://www.hark.com/clips/mmbzyhkgny-obama-beyond-the-afghan-theater-we-only-target-al-qaeda-on-may-23-2013',
+        u'file': u'mmbzyhkgny.mp3',
+        u'md5': u'6783a58491b47b92c7c1af5a77d4cbee',
+        u'info_dict': {
+            u"title": u"Obama: 'Beyond The Afghan Theater, We Only Target Al Qaeda' On May 23, 2013 ",
+        }
+    }
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        video_id = mobj.group(1)
+        embed_url = "http://www.hark.com/clips/%s/homepage_embed" %(video_id)
+        webpage = self._download_webpage(embed_url, video_id)
+
+        final_url = self._search_regex(r'src="(.+?).mp3"',
+                                webpage, 'video url')+'.mp3'
+        title = self._html_search_regex(r'<title>(.+?)</title>',
+                                webpage, 'video title').replace(' Sound Clip and Quote - Hark','').replace(
+                                'Sound Clip , Quote, MP3, and Ringtone - Hark','')
+
+        return {'id': video_id,
+                'url' : final_url,
+                'title': title,
+                'ext': determine_ext(final_url),
+                }


Test patch:
Repository: ytdl-org/youtube-dl

Issue:
Updated Vevo Signature Length
Decryption function:

```
function lj(a) {
    a = a.split("");
    a = mj(a, 52);
    a = a.reverse();
    a = mj(a, 18);
    a = a.reverse();
    a = a.slice(1);
    a = mj(a, 44);
    a = mj(a, 51);
    a = a.reverse();
    a = a.slice(1);
    return a.join("")
}

function mj(a, b) {
    var c = a[0];
    a[0] = a[b % a.length];
    a[b] = c;
    return a
};
```



Discussion:
new sig len 83 algo:

pairs:
4B8D03C157C3837742A0AA47AEF3D295CFFAAC476.7191265775BE8AC3130CB2CACE67A620B0CAA64C3
C46AAC0B026A76ECA32BC0313CA8E1577562B917.674CAAFFC592D3FEA74AA0A2477383C751C30D84

D48C4F5F9128645C70B98AA69E0CA24D35E69A098.940B9CC7A044E47A56DCCACAFE8EA619B134240C2
C042431B916AE8EFA2ACCD65A74E4B0A7CC94049.890A96E53D42AC0E96AA89B07C5468219F5F4C8D

python:
s[81:64:-1] + s[82] + s[63:52:-1] + s[45] + s[51:45:-1] + s[1] + s[44:1:-1] + s[0]

javascript
s.slice(65, 82).reverse().join('') + s[82] + s.slice(53, 64).reverse().join('') + s[45] + s.slice(46, 52).reverse().join('') + s[1] + s.slice(2, 45).reverse().join('') + s[0]


Resolving patch:
diff --git a/youtube_dl/extractor/youtube.py b/youtube_dl/extractor/youtube.py
--- a/youtube_dl/extractor/youtube.py
+++ b/youtube_dl/extractor/youtube.py
@@ -348,7 +348,7 @@ def _decrypt_signature(self, s):
         elif len(s) == 84:
             return s[83:27:-1] + s[0] + s[26:5:-1] + s[2:0:-1] + s[27]
         elif len(s) == 83:
-            return s[:15] + s[80] + s[16:80] + s[15]
+            return s[81:64:-1] + s[82] + s[63:52:-1] + s[45] + s[51:45:-1] + s[1] + s[44:1:-1] + s[0]
         elif len(s) == 82:
             return s[36] + s[79:67:-1] + s[81] + s[66:40:-1] + s[33] + s[39:36:-1] + s[40] + s[35] + s[0] + s[67] + s[32:0:-1] + s[34]
         elif len(s) == 81:


Test patch:
Repository: ytdl-org/youtube-dl

Issue:
Vevo sig changed again, please update for us! Thanks very much!



Discussion:
new sig len 86 algo:

pair:

C116111EC82F1B7B0FCB46E0C219589D4E61A4.F8E0A419BBD6129355BF133B7AE416BD6AA9E964D94C398
11EC82F1B7B0FCB46E0C219589D4EC1A46F8E0A4.9BBD612A355BF133B7AE416BD6A89E964D94C399

python:
s[5:34] + s[0] + s[35:38] + s[3] + s[39:45] + s[38] + s[46:53] + s[73] + s[54:73] + s[85] + s[74:85] + s[53]

javascript:
s.slice(5, 34).join('') + s[0] + s.slice(35, 38).join('') + s[3] + s.slice(39, 45).join('') + s[38] + s.slice(46, 53).join('') + s[73] + s.slice(54, 73).join('') + s[85] + s.slice(74, 85).join('') + s[53]


Resolving patch:
diff --git a/youtube_dl/extractor/youtube.py b/youtube_dl/extractor/youtube.py
--- a/youtube_dl/extractor/youtube.py
+++ b/youtube_dl/extractor/youtube.py
@@ -436,7 +436,7 @@ def _decrypt_signature(self, s):
         elif len(s) == 87:
             return s[6:27] + s[4] + s[28:39] + s[27] + s[40:59] + s[2] + s[60:]
         elif len(s) == 86:
-            return s[81:73:-1] + s[84] + s[72:58:-1] + s[0] + s[57:35:-1] + s[85] + s[34:0:-1]
+            return s[5:34] + s[0] + s[35:38] + s[3] + s[39:45] + s[38] + s[46:53] + s[73] + s[54:73] + s[85] + s[74:85] + s[53]
         elif len(s) == 85:
             return s[83:34:-1] + s[0] + s[33:27:-1] + s[3] + s[26:19:-1] + s[34] + s[18:3:-1] + s[27]
         elif len(s) == 84:


Test patch:
Repository: ytdl-org/youtube-dl

Issue:
Support for the Newgrounds Audio Portal?
Following Soundcloud support, I feel that adding Newgrounds support would be a logical step.
Most tracks on there are already easily downloadable from the webpage, it'd be nice to add it to the list.

Thoughts?



Discussion:

Resolving patch:
diff --git a/youtube_dl/extractor/__init__.py b/youtube_dl/extractor/__init__.py
--- a/youtube_dl/extractor/__init__.py
+++ b/youtube_dl/extractor/__init__.py
@@ -68,6 +68,7 @@
 from .naver import NaverIE
 from .nba import NBAIE
 from .nbc import NBCNewsIE
+from .newgrounds import NewgroundsIE
 from .ooyala import OoyalaIE
 from .orf import ORFIE
 from .pbs import PBSIE
diff --git a/youtube_dl/extractor/newgrounds.py b/youtube_dl/extractor/newgrounds.py
new file mode 100644
--- /dev/null
+++ b/youtube_dl/extractor/newgrounds.py
@@ -0,0 +1,37 @@
+import json
+import re
+
+from .common import InfoExtractor
+from ..utils import determine_ext
+
+class NewgroundsIE(InfoExtractor):
+    _VALID_URL = r'(?:https?://)?(?:www\.)?newgrounds\.com/audio/listen/(?P<id>\d+)'
+    _TEST = {
+        u'url': u'http://www.newgrounds.com/audio/listen/549479',
+        u'file': u'549479.mp3',
+        u'md5': u'fe6033d297591288fa1c1f780386f07a',
+        u'info_dict': {
+            u"title": u"B7 - BusMode",
+            u"uploader" : u"Burn7",
+        }
+    }
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        music_id = mobj.group('id')
+        webpage = self._download_webpage(url, music_id)
+        
+        title = self._html_search_regex(r',"name":"([^"]+)",', webpage, 'music title', flags=re.DOTALL)
+        uploader = self._html_search_regex(r',"artist":"([^"]+)",', webpage, 'music uploader', flags=re.DOTALL)
+        
+        music_url_json_string = '{"url":"' + self._html_search_regex(r'{"url":"([^"]+)",', webpage, 'music url', flags=re.DOTALL) + '"}'
+        music_url_json = json.loads(music_url_json_string)
+        music_url = music_url_json['url']
+
+        return [{
+            'id':       music_id,
+            'title':    title,            
+            'url':      music_url,
+            'uploader': uploader,
+            'ext':      determine_ext(music_url),
+        }]


Test patch:
Repository: ytdl-org/youtube-dl

Issue:
Resolutions Printed by -F Are Misleading
The resolutions printed by -F list resolutions in height x width format, such as, for example:

45 : webm [720x1280]

which is misleading since resolution is almost always given as width x height rather than height x width in everything other than YouTube-DL.



Discussion:
Are patches for this wanted? They really confuse me as well, as this is backwards of what everybody would expect.

It could be changed to 720p as other formats.

> > Are patches for this wanted? They really confuse me as well, as this is backwards of what everybody would expect.

Yes, a patch for this would be great, especially as it seems a fairly simple fix to make to just switch the order of the two numbers.


Resolving patch:
diff --git a/youtube_dl/extractor/youtube.py b/youtube_dl/extractor/youtube.py
--- a/youtube_dl/extractor/youtube.py
+++ b/youtube_dl/extractor/youtube.py
@@ -253,21 +253,21 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor):
         '248': 'webm',
     }
     _video_dimensions = {
-        '5': '240x400',
+        '5': '400x240',
         '6': '???',
         '13': '???',
-        '17': '144x176',
-        '18': '360x640',
-        '22': '720x1280',
-        '34': '360x640',
-        '35': '480x854',
-        '36': '240x320',
-        '37': '1080x1920',
-        '38': '3072x4096',
-        '43': '360x640',
-        '44': '480x854',
-        '45': '720x1280',
-        '46': '1080x1920',
+        '17': '176x144',
+        '18': '640x360',
+        '22': '1280x720',
+        '34': '640x360',
+        '35': '854x480',
+        '36': '320x240',
+        '37': '1920x1080',
+        '38': '4096x3072',
+        '43': '640x360',
+        '44': '854x480',
+        '45': '1280x720',
+        '46': '1920x1080',
         '82': '360p',
         '83': '480p',
         '84': '720p',


Test patch:
Repository: ytdl-org/youtube-dl

Issue:
add tvp.pl support
there's need only to add to yt-dl: https://github.com/mplonski/linux/blob/master/tvp-dl.py



Discussion:
Do you put that source code under [Unlicense](http://unlicense.org/)? I can't find any License declaration for that project.

Additionally, it would be nice if you could post an example URL which we can then use to test our implementation.

My source code is under Unlicense :) (I've changed it a minute ago.) Example URL is inside the code, line 39 (just run this script to see short manual).


Resolving patch:
diff --git a/youtube_dl/extractor/__init__.py b/youtube_dl/extractor/__init__.py
--- a/youtube_dl/extractor/__init__.py
+++ b/youtube_dl/extractor/__init__.py
@@ -132,6 +132,7 @@
 from .tudou import TudouIE
 from .tumblr import TumblrIE
 from .tutv import TutvIE
+from .tvp import TvpIE
 from .unistra import UnistraIE
 from .ustream import UstreamIE, UstreamChannelIE
 from .vbox7 import Vbox7IE
diff --git a/youtube_dl/extractor/tvp.py b/youtube_dl/extractor/tvp.py
new file mode 100644
--- /dev/null
+++ b/youtube_dl/extractor/tvp.py
@@ -0,0 +1,60 @@
+# encoding: utf-8
+import re
+import json
+
+from .common import InfoExtractor
+from ..utils import (
+    determine_ext,
+    ExtractorError,
+    RegexNotFoundError,
+)
+
+class TvpIE(InfoExtractor):
+    IE_NAME = u'tvp.pl'
+    _VALID_URL = r'https?://www\.tvp\.pl/.*?wideo/(?P<date>\d+)/(?P<id>\d+)'
+    _INFO_URL = 'http://www.tvp.pl/pub/stat/videofileinfo?video_id=%s'
+
+
+    _TEST = {
+        u'url': u'http://www.tvp.pl/warszawa/magazyny/campusnews/wideo/31102013/12878238',
+        u'file': u'31.10.2013-12878238.wmv',
+        u'info_dict': {
+            u'title': u'31.10.2013',
+            u'description': u'31.10.2013',
+        },
+    }
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        video_id = mobj.group('id')
+        webpage = self._download_webpage(url, video_id, "Downloading video webpage")
+        json_params = self._download_webpage(self._INFO_URL % video_id, video_id, "Downloading video metadata")
+
+        try:
+            params = json.loads(json_params)
+        except:
+            raise ExtractorError(u'Invalid JSON')
+
+        self.report_extraction(video_id)
+        try:
+            video_url = params['video_url']
+        except KeyError:
+            raise ExtractorError('Missing JSON parameter: ' + sys.exc_info()[1])
+
+        try:
+            title = self._og_search_title(webpage)
+        except RegexNotFoundError:
+            title = video_id
+        info = {
+            'id': video_id,
+            'title': title,
+            'ext': 'wmv',
+            'url': video_url,
+        }
+        try:
+            info['description'] = self._og_search_description(webpage)
+            info['thumbnail'] = self._og_search_thumbnail(webpage)
+        except RegexNotFoundError:
+            pass
+
+        return info


Test patch:
Repository: ytdl-org/youtube-dl

Issue:
Log to an external logger
Sadly applications using youtube-dl's python sources can't directly access it's log stream. It's pretty much limited to stdout and stderr only.

It should log to logging.Logger instance passed to YoutubeDL's params dictionary.

Log to an external logger
Sadly applications using youtube-dl's python sources can't directly access it's log stream. It's pretty much limited to stdout and stderr only.

It should log to logging.Logger instance passed to YoutubeDL's params dictionary.



Discussion:

Resolving patch:
diff --git a/youtube_dl/YoutubeDL.py b/youtube_dl/YoutubeDL.py
--- a/youtube_dl/YoutubeDL.py
+++ b/youtube_dl/YoutubeDL.py
@@ -97,6 +97,7 @@ class YoutubeDL(object):
     playlistend:       Playlist item to end at.
     matchtitle:        Download only matching titles.
     rejecttitle:       Reject downloads for matching titles.
+	logger:            Log messages to a logging.Logger instance.
     logtostderr:       Log messages to stderr instead of stdout.
     writedescription:  Write the video description to a .description file
     writeinfojson:     Write the video description to a .info.json file
@@ -192,7 +193,9 @@ def add_post_processor(self, pp):
 
     def to_screen(self, message, skip_eol=False):
         """Print message to stdout if not in quiet mode."""
-        if not self.params.get('quiet', False):
+        if self.params.get('logger', False):
+            self.params['logger'].debug(message)
+        elif not self.params.get('quiet', False):
             terminator = [u'\n', u''][skip_eol]
             output = message + terminator
             write_string(output, self._screen_file)
@@ -200,10 +203,13 @@ def to_screen(self, message, skip_eol=False):
     def to_stderr(self, message):
         """Print message to stderr."""
         assert type(message) == type(u'')
-        output = message + u'\n'
-        if 'b' in getattr(self._screen_file, 'mode', '') or sys.version_info[0] < 3: # Python 2 lies about the mode of sys.stdout/sys.stderr
-            output = output.encode(preferredencoding())
-        sys.stderr.write(output)
+        if self.params.get('logger', False):
+            self.params['logger'].error(message)
+        else:
+            output = message + u'\n'
+            if 'b' in getattr(self._screen_file, 'mode', '') or sys.version_info[0] < 3: # Python 2 lies about the mode of sys.stdout/sys.stderr
+                output = output.encode(preferredencoding())
+            sys.stderr.write(output)
 
     def to_console_title(self, message):
         if not self.params.get('consoletitle', False):


Test patch: