Repository: streamlink/streamlink

Issue:
Streamlink no longer provides streamlink-script.py
As of version 0.14.0 streamlink does not install the streamlink-script.py script,
because of this streamlink-twitch-gui does not work as it cannot load the script.
This may an issue in streamlink, as there is no mention of its removal in the changelog.


Discussion:
Which OS are you using and which method of installing Streamlink did you choose?
I am using Windows 10, and streamlink is installed via pip.
Also I am using python 3.
That's because of streamlink/streamlink#1701 / streamlink/streamlink#1758 and a change of the python wheel packaging.

I'll see what I can do about this. Maybe I have to add a "Streamlink standalone" option, just like "Livestreamer standalone", but this may conflict with Streamlink portable, as it also generates a .exe file on Windows which is not usable at all.

If you install Streamlink on Windows via pip, you can work around this for now by using the `--no-binary streamlink` parameter+value, like this:
```
pip uninstall streamlink
pip install --no-binary streamlink streamlink
```
```
pip install --help | grep -A8 'no-binary'
  --no-binary <format_control>
                              Do not use binary packages. Can be supplied
                              multiple times, and each time adds to the
                              existing value. Accepts either :all: to disable
                              all binary packages, :none: to empty the set, or
                              one or more package names with commas between
                              them. Note that some packages are tricky to
                              compile and may fail to install when this option
                              is used on them.
```

/cc @beardypig 
I’ll investigate as this seems to be a packaging issue. 
I can confirm this, i'm not getting the script.
Has there been any progress on the fix for this?
Streamlink has released v1.0.0, which would imply that the majority of developers
there believe that the program has no major issues.
Also @beardypig while you said you would investigate this,
you did not open an issue at the streamlink repository so the other developers there
would know there was an issue with a closely associated application.
> streamlink-twitch-gui does not work as it cannot load the script.

there is a **streamlink.exe** file which can open the streams with streamlink-twitch-gui

you can find it in _(depends on your python location)_

`%LOCALAPPDATA%\Programs\Python\Python37-32\Scripts\streamlink.exe`

my tested `Streamlink Pythonscript` was

`C:\Users\win\AppData\Local\Programs\Python\Python37-32\Scripts\streamlink.exe`

---

the exe files works with a normal `python -m pip install -U streamlink`

don't use the exe file from `pip install --no-binary streamlink streamlink` this won't work
> there is a **streamlink.exe** file which can open the streams with streamlink-twitch-gui

No, that doesn't work.

The Twitch GUI's streamlink resolver expects a python executable and a streamlink entry script. Up until the point of this packaging change, there was no reason to implement a resolver config for a streamlink wrapper executable.

Before the fork of Streamlink, Livestreamer required two different resolver configs, one for its standalone release, which included a single executable, and one for the pip package, which included the entry script and a wrapper executable. Since the wrapper executable always opened a terminal window, it wasn't useful for being run from a GUI application and a second resolver config had to be implemented that used the regular python executable and the entry script. That's the reason for the two ["Livestreamer standalone" and "Livestreamer"](https://github.com/streamlink/streamlink-twitch-gui/blob/v1.6.0/src/config/streaming.json#L72-L127) resolver configs in the Twitch GUI.

The ["Streamlink"](https://github.com/streamlink/streamlink-twitch-gui/blob/v1.6.0/src/config/streaming.json#L25-L71) resolver config is basically a copy of the "Livestreamer" one, as it also expects a python executable and an entry script. This wasn't a problem until recently, because all install methods on Windows included both of these requirements. Now, with this pip packaging change, a secondary Streamlink resolver config would be needed, but I fear that this will cause more confusion than solve issues. And I'm also not sure if the terminal window issue will occur.

A better way of solving this problem would be including both the wrapper executable and entry script in the pip package on Windows, just like Livestreamer did.

But as I've said in my previous comment, the workaround of suppressing the binary works just fine, as it won't omit the entry script.
> A better way of solving this problem would be including both the wrapper executable and entry script in the pip package on Windows, just like Livestreamer did.

sure it could be done, but my point was that it already works **without any changes**

> > there is a **streamlink.exe** file which can open the streams with streamlink-twitch-gui
> 
> No, that doesn't work.

works for me

> The Twitch GUI's streamlink resolver expects a python executable and a streamlink entry script. Up until the point of this packaging change,

there is a `pythonw.exe` and `streamlink.exe`

---

I tested it with a fresh install

- new windows 10 virtual machine
- vlc install
- python 3.7.2 install with https://www.python.org/ftp/python/3.7.2/python-3.7.2-amd64.exe
- cmd: `python -m pip install streamlink` **(important use the .whl not .tar.gz)**
- streamlink-twitch-gui install with `streamlink-twitch-gui-v1.6.0-win64-installer.exe`
- config streamlink-twitch-gui

ALl user

```
Python
C:\Program Files (x86)\Python37-32\pythonw.exe

Streamlink
C:\Program Files (x86)\Python37-32\Scripts\streamlink.exe
```

or

current user

```
Python
C:\Users\new\AppData\Local\Programs\Python\Python37-32\pythonw.exe

Streamlink
C:\Users\new\AppData\Local\Programs\Python\Python37-32\Scripts\streamlink.exe
```
- open a random stream with vlc

Streamlink starts as expected

---

> because of this streamlink-twitch-gui does not work as it cannot load the script.

so this is invalid
Just to confirm that setting the streamlink.exe file as the Streamlink python script appears to work fine. It would be cool if it was set to this out of the box though!

![2019-02-05 15_42_35-streamlink twitch gui](https://user-images.githubusercontent.com/400279/52284619-ab595800-295c-11e9-8073-93cedc274bf6.png)

> my point was that it already works **without any changes**

It only works if the user has set custom paths, which doesn't really mean *without any changes*. This is an **undocumented breaking packaging change** and we should fix this.

Sure, this can (and will be) fixed in the Twitch GUI's next release with an upgraded default resolver config, but other applications could be affected by this, too.
Hm, so this seems to be a bit more difficult than I thought. Let me try to explain:

The packaging change was introduced by pynist on Nov 6th after the change in takluyver/pynsist#169. The regular [entry scripts were removed](https://github.com/takluyver/pynsist/pull/169/files#diff-082101e7ff364358b0b29162a1e4a4a9L41) during the switch from `win_cli_launchers` to `distlib` for building the wrapper executables, as that's what pip seems to be using nowadays. This removal is unfortunately breaking the Streamlink Twitch GUI, because of the way it has to resolve and verify the Streamlink entry script and python executable on Windows.

----

Here is how this works:

If a user has set custom paths in the Twitch GUI (as shown in the comments above), no entry-script and executable resolving has to be done, as it's up to the user to select the right files. In case the python executable is not set, it'll use the the `PATH` env var for looking it up and the user has to make sure that the correct python version is used.

If however no custom paths are set, the Twitch GUI has to find the right files on its own, and this unfortunately requires a workaround on Windows. The reason for that is that you can't simply execute the `streamlink.exe` wrapper executable from within the GUI, as it uses `python.exe` instead of `pythonw.exe`, and a terminal window will be opened, which is pretty annoying. Because of this, `pythonw.exe` has to be resolved from reading the shebang of the entry script (it actually reads the `dirname` of this path and looks up `pythonw.exe` in there, because the shebang also references the unwanted `python.exe`).
A quicker alternative to this could be looking up `streamlink-script.py`/`streamlink.exe` and `pythonw.exe` individually from the system's `PATH` env var, but that method is not good enough, as the user could have a global python environment installed and its path could be registered in the `PATH` env var before the one of Streamlink. That could lead to a python version mismatch. Reading the shebang of the entry script is therefore required.

But now, since there's no entry script included anymore in the installer, all you can do is try to read the shebang from the file embedded in the wrapper executable (a zip archive?!), and that's stupid. or you could guess a relative path from that file where `pythonw.exe` is located, but that's equally stupid.

----

The removal of the entry scripts from pynist is a breaking change, but they didn't bump their major version. We could fix this here (temporarily) by downgrading, or the removal could be reverted in pynsist if the dev(s) can be convinced.

Regarding pip, is there a way to make pip always ignore the binary, so one doesn't have to set the `--no-binary streamlink` parameter, like for example a certain packaging flag?

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -1,8 +1,7 @@
 #!/usr/bin/env python
 import codecs
-from os import environ
-from os import path
-from sys import path as sys_path
+from os import environ, path
+from sys import argv, path as sys_path
 
 from setuptools import setup, find_packages
 
@@ -53,6 +52,27 @@
 with codecs.open(path.join(this_directory, "README.md"), 'r', "utf8") as f:
     long_description = f.read()
 
+
+def is_wheel_for_windows():
+    if "bdist_wheel" in argv:
+        names = ["win32", "win-amd64", "cygwin"]
+        length = len(argv)
+        for pos in range(argv.index("bdist_wheel") + 1, length):
+            if argv[pos] == "--plat-name" and pos + 1 < length:
+                return argv[pos + 1] in names
+            elif argv[pos][:12] == "--plat-name=":
+                return argv[pos][12:] in names
+    return False
+
+
+entry_points = {
+    "console_scripts": ["streamlink=streamlink_cli.main:main"]
+}
+
+if is_wheel_for_windows():
+    entry_points["gui_scripts"] = ["streamlinkw=streamlink_cli.main:main"]
+
+
 setup(name="streamlink",
       version=versioneer.get_version(),
       cmdclass=versioneer.get_cmdclass(),
@@ -74,9 +94,7 @@
       license="Simplified BSD",
       packages=find_packages("src"),
       package_dir={"": "src"},
-      entry_points={
-          "console_scripts": ["streamlink=streamlink_cli.main:main"]
-      },
+      entry_points=entry_points,
       install_requires=deps,
       test_suite="tests",
       python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4",


Test patch: