Repository: ytdl-org/youtube-dl

Issue:
Downloads fail on Windows with Python 2.7.13
## Please follow the guide below

- You will be asked some questions and requested to provide some information, please read them **carefully** and answer honestly
- Put an `x` into all the boxes [ ] relevant to your *issue* (like that [x])
- Use *Preview* tab to see how your issue will actually look like

---

### Make sure you are using the *latest* version: run `youtube-dl --version` and ensure your version is *2016.12.22*. If it's not read [this FAQ entry](https://github.com/rg3/youtube-dl/blob/master/README.md#how-do-i-update-youtube-dl) and update. Issues with outdated version will be rejected.
- [X ] I've **verified** and **I assure** that I'm running youtube-dl **2016.12.22**

### Before submitting an *issue* make sure you have:
- [X ] At least skimmed through [README](https://github.com/rg3/youtube-dl/blob/master/README.md) and **most notably** [FAQ](https://github.com/rg3/youtube-dl#faq) and [BUGS](https://github.com/rg3/youtube-dl#bugs) sections
- [X ] [Searched](https://github.com/rg3/youtube-dl/search?type=Issues) the bugtracker for similar issues including closed ones

### What is the purpose of your *issue*?
- [X] Bug report (encountered problems with youtube-dl)
- [ ] Site support request (request for adding support for a new site)
- [ ] Feature request (request for a new functionality)
- [ ] Question
- [ ] Other

---

### The following sections concretize particular purposed issues, you can erase any section (the contents between triple ---) not applicable to your *issue*

---

### If the purpose of this *issue* is a *bug report*, *site support request* or you are not completely sure provide the full verbose output as follows:

Add `-v` flag to **your command line** you run youtube-dl with, copy the **whole** output and insert it here. It should look similar to one below (replace it with **your** log inserted between triple ```):
```
21:14:47.44 ++c:\s\yt>c:\Python27\Scripts\youtube-dl.exe -v
Traceback (most recent call last):
  File "c:\python27\lib\runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "c:\python27\lib\runpy.py", line 72, in _run_code
    exec code in run_globals
  File "c:\Python27\Scripts\youtube-dl.exe\__main__.py", line 9, in <module>
  File "c:\python27\lib\site-packages\youtube_dl\__init__.py", line 444, in main
    _real_main(argv)
  File "c:\python27\lib\site-packages\youtube_dl\__init__.py", line 56, in _real_main
    setproctitle('youtube-dl')
  File "c:\python27\lib\site-packages\youtube_dl\utils.py", line 1665, in setproctitle
    libc = ctypes.cdll.LoadLibrary('libc.so.6')
  File "c:\python27\lib\ctypes\__init__.py", line 440, in LoadLibrary
    return self._dlltype(name)
  File "c:\python27\lib\ctypes\__init__.py", line 362, in __init__
    self._handle = _dlopen(self._name, mode)
TypeError: LoadLibrary() argument 1 must be string, not unicode

21:15:32.69 ++c:\s\yt>
```
(Note this fails before any [debug] output)
---

### If the purpose of this *issue* is a *site support request* please provide all kinds of example URLs support for which should be included (replace following example URLs by **yours**):
- Single video: https://www.youtube.com/watch?v=BaW_jenozKc
- Single video: https://youtu.be/BaW_jenozKc
- Playlist: https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc

---

### Description of your *issue*, suggested solution and other information
    
In Python 2.7.13, the Windows version of LoadLibrary requires a string, not a unicode arg. This is due to a change in Python-2.7.12\Modules\_ctypes\callproc.c vs. Python-2.7.13\Modules\_ctypes\callproc.c:
In:
    static PyObject *load_library(PyObject *self, PyObject *args)
there is this change (from 2.7.12 to 2.7.13):
    1280c1284
    <     if (!PyArg_ParseTuple(args, "O|O:LoadLibrary", &nameobj, &ignored))
    ---
    >     if (!PyArg_ParseTuple(args, "S|O:LoadLibrary", &nameobj, &ignored))

I was going to propose just changing:
        libc = ctypes.cdll.LoadLibrary('libc.so.6')
to:
        libc = ctypes.cdll.LoadLibrary(b'libc.so.6')
in utils.py, which does fix the TypeError, but I find that this TypeError does not occur under Python 3.6.0, apparently because callproc.c in 3.6.0 does not have the change shown above. Since this call to LoadLibrary() should fail under Windows anyway, maybe the correct fix is to have setproctitle() in utils.py just return if the LoadLibrary() raises either TypeError or OSError. 

Is is correct under either Python 2 or 3 to pass a unicode string to LoadLibrary() in either Windows or Posix? Should b'libc.so.6' be used in all cases (Windows, Posix/Linux, Python 2 or 3)? I note that in Linux (Posix) environment, the LoadLibrary() call goes to py_dl_open() instead of load_library(), and it also does not have the "S" typecheck in 2.7.13 or in 3.6.0.




Discussion:
Thanks for the report and detailed investigation. I hope it fixed upstream and filed http://bugs.python.org/issue29082
Here's a summary:

Version | _ctypes.dlopen() | _ctypes.LoadLibrary()
--- | --- | ---
2.7.12 | S & U | S & U
2.7.13 | S & U | S
3.x | S & U | U

Here S and U indicate bytes and unicode objects, respectively.
Fixed in CPython - https://hg.python.org/cpython/rev/4ce22d69e134

This issue can be closed if Python 2.7.14 is released, which is likely to happen in mid-2017. See https://www.python.org/dev/peps/pep-0373/. Before that please downgrade to 2.7.12.

Resolving patch:
diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py
--- a/youtube_dl/utils.py
+++ b/youtube_dl/utils.py
@@ -1684,6 +1684,11 @@ def setproctitle(title):
         libc = ctypes.cdll.LoadLibrary('libc.so.6')
     except OSError:
         return
+    except TypeError:
+        # LoadLibrary in Windows Python 2.7.13 only expects
+        # a bytestring, but since unicode_literals turns
+        # every string into a unicode string, it fails.
+        return
     title_bytes = title.encode('utf-8')
     buf = ctypes.create_string_buffer(len(title_bytes))
     buf.value = title_bytes


Test patch: