From 98e6a066f4d6e52fb97702a929264d38a16ecb0a Mon Sep 17 00:00:00 2001
From: Brannon King <countprimes@gmail.com>
Date: Wed, 4 Mar 2020 15:53:46 -0700
Subject: [PATCH 1/3] add unit test and debug output

---
 lbry/file_analysis.py                       | 4 ++--
 tests/integration/other/test_transcoding.py | 5 +++++
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/lbry/file_analysis.py b/lbry/file_analysis.py
index 0a9476b65..d0e99c47c 100644
--- a/lbry/file_analysis.py
+++ b/lbry/file_analysis.py
@@ -37,10 +37,10 @@ class VideoFileAnalyzer:
         try:
             version, code = await self._execute(name, "-version")
         except Exception as e:
-            log.warning("Unable to run %s, but it was requested. Message: %s", name, str(e))
             code = -1
-            version = ""
+            version = str(e)
         if code != 0 or not version.startswith(name):
+            log.warning("Unable to run %s, but it was requested. Code: %d; Message: %s", name, code, version)
             raise FileNotFoundError(f"Unable to locate or run {name}. Please install FFmpeg "
                                     f"and ensure that it is callable via PATH or conf.ffmpeg_folder")
         return version
diff --git a/tests/integration/other/test_transcoding.py b/tests/integration/other/test_transcoding.py
index 60cad7992..08ea9fe00 100644
--- a/tests/integration/other/test_transcoding.py
+++ b/tests/integration/other/test_transcoding.py
@@ -93,6 +93,11 @@ class TranscodeValidation(ClaimTestCase):
         fixed_file = await self.analyzer.verify_or_repair(True, True, file_name)
         pathlib.Path(fixed_file).unlink()
 
+    async def test_max_bit_rate(self):
+        self.conf.video_bitrate_maximum = 100
+        with self.assertRaisesRegex(Exception, "The bit rate is above the configured maximum"):
+            await self.analyzer.verify_or_repair(True, False, self.video_file_name)
+
     async def test_video_format(self):
         file_name = self.make_name("bad_video_format_1")
         if not file_name.exists():

From dec248adeccb973f5f891a319c757302f3b69eee Mon Sep 17 00:00:00 2001
From: Brannon King <countprimes@gmail.com>
Date: Wed, 4 Mar 2020 17:08:47 -0700
Subject: [PATCH 2/3] repair env modified by pyinstaller

see https://pyinstaller.readthedocs.io/en/stable/runtime-information.html#ld-library-path-libpath-considerations
---
 lbry/file_analysis.py | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/lbry/file_analysis.py b/lbry/file_analysis.py
index d0e99c47c..3b9a25878 100644
--- a/lbry/file_analysis.py
+++ b/lbry/file_analysis.py
@@ -15,12 +15,20 @@ DISABLED = platform.system() == "Windows"
 
 class VideoFileAnalyzer:
 
+    def _replace_or_pop_env(self, variable):
+        if variable + '_ORIG' in self._env_copy:
+            self._env_copy[variable] = self._env_copy[variable + '_ORIG']
+        else:
+            self._env_copy.pop(variable, None)
+
     def __init__(self, conf: TranscodeConfig):
         self._conf = conf
         self._available_encoders = ""
         self._ffmpeg_installed = False
         self._which = None
         self._checked_ffmpeg = False
+        self._env_copy = dict(os.environ)
+        self._replace_or_pop_env('LD_LIBRARY_PATH')
 
     async def _execute(self, command, arguments):
         if DISABLED:
@@ -28,7 +36,7 @@ class VideoFileAnalyzer:
         args = shlex.split(arguments)
         process = await asyncio.create_subprocess_exec(
             os.path.join(self._conf.ffmpeg_folder, command), *args,
-            stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
+            stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, env=self._env_copy
         )
         stdout, stderr = await process.communicate()  # returns when the streams are closed
         return stdout.decode(errors='replace') + stderr.decode(errors='replace'), process.returncode

From 212c8f188d6ed564e7489fceb699a51bedf84344 Mon Sep 17 00:00:00 2001
From: Brannon King <countprimes@gmail.com>
Date: Fri, 6 Mar 2020 11:31:17 -0700
Subject: [PATCH 3/3] only change LD vars if running from bundle

missed a word


moved is_running_from_bundle
---
 lbry/file_analysis.py | 6 +++++-
 lbry/utils.py         | 6 ++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/lbry/file_analysis.py b/lbry/file_analysis.py
index 3b9a25878..550ffc6a1 100644
--- a/lbry/file_analysis.py
+++ b/lbry/file_analysis.py
@@ -7,6 +7,8 @@ import re
 import shlex
 import shutil
 import platform
+
+import lbry.utils
 from lbry.conf import TranscodeConfig
 
 log = logging.getLogger(__name__)
@@ -28,7 +30,9 @@ class VideoFileAnalyzer:
         self._which = None
         self._checked_ffmpeg = False
         self._env_copy = dict(os.environ)
-        self._replace_or_pop_env('LD_LIBRARY_PATH')
+        if lbry.utils.is_running_from_bundle():
+            # handle the situation where PyInstaller overrides our runtime environment:
+            self._replace_or_pop_env('LD_LIBRARY_PATH')
 
     async def _execute(self, command, arguments):
         if DISABLED:
diff --git a/lbry/utils.py b/lbry/utils.py
index 65d33b3e2..c24d8a971 100644
--- a/lbry/utils.py
+++ b/lbry/utils.py
@@ -4,6 +4,7 @@ import datetime
 import random
 import socket
 import string
+import sys
 import json
 import typing
 import asyncio
@@ -276,3 +277,8 @@ async def get_external_ip() -> typing.Optional[str]:  # used if upnp is disabled
                 return response['data']['ip']
     except Exception:
         return
+
+
+def is_running_from_bundle():
+    # see https://pyinstaller.readthedocs.io/en/stable/runtime-information.html
+    return getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS')