# Buggy code
def blocks_r(filename, size=64 * 1024, reset_offset=True):
    """
    Yields the data within a file in reverse-ordered blocks of given size.

    This code is part of the flyingcircus package: https://pypi.org/project/flyingcircus/
    The code was adapted for our use case.
    All credits go to the original author.

    Note that:
     - the content of the block is NOT reversed.

    Args:
        filename (str): The input file name.
        size (int|None): The block size.
            If int, the file is yielded in blocks of the specified size.
            If None, the file is yielded at once.
        reset_offset (bool): Reset the file offset.
            If True, starts reading from the end of the file.
            Otherwise, starts reading from where the file current position is.

    Yields:
        block (bytes): The data within the blocks.

    """
    with io.open(filename, "rb") as file_obj:
        offset = 0
        if reset_offset:
            file_size = remaining_size = file_obj.seek(0, os.SEEK_END)
        else:
            file_size = remaining_size = file_obj.tell()
        rounding = 0
        while remaining_size > 0:
            offset = min(file_size, offset + size)
            file_obj.seek(file_size - offset)
            block = file_obj.read(min(remaining_size, size))
            remaining_size -= size
            yield block[: len(block) + rounding] if rounding else block


# Traceback (UnicodeDecodeError)
2018-10-20 09:11:56 INFO     SHOWQUEUE-ADD :: [4614efc] Starting to add show by ShowDir: /volume1/TV-Series/TV Series/Bull (2016)
2018-10-20 09:11:56 INFO     SHOWQUEUE-ADD :: [4614efc] TMDB: {u'session': <medusa.session.core.MedusaSession object at 0x7f21cae43e90>, u'cache': u'/volume1/@appstore/sickbeard-custom/var/cache/indexers/TMDB', u'language': u'en', u'use_zip': True}
2018-10-20 09:11:59 INFO     SHOWQUEUE-ADD :: [4614efc] 66840: Unable to find the show in the database
2018-10-20 09:11:59 INFO     SHOWQUEUE-ADD :: [4614efc] Setting all previously aired episodes to the specified status: Skipped
2018-10-20 09:12:08 INFO     SHOWQUEUE-ADD :: [4614efc] Updating exception_cache and exception_season_cache
2018-10-20 09:12:08 INFO     SHOWQUEUE-ADD :: [4614efc] Finished processing 2904 scene exceptions.
2018-10-20 09:12:08 INFO     SHOWQUEUE-ADD :: [4614efc] Building internal name cache for Bull
2018-10-20 09:12:08 ERROR    SHOWQUEUE-ADD :: [4614efc] Error searching dir for episodes: 'utf8' codec can't decode byte 0x92 in position 26: invalid start byte
Traceback (most recent call last):
  File "/volume1/@appstore/sickbeard-custom/var/SickBeard/medusa/show_queue.py", line 617, in run
    self.show.load_episodes_from_dir()
  File "/volume1/@appstore/sickbeard-custom/var/SickBeard/medusa/tv/series.py", line 985, in load_episodes_from_dir
    media_files = helpers.list_media_files(self.location)
  File "/volume1/@appstore/sickbeard-custom/var/SickBeard/medusa/helpers/__init__.py", line 262, in list_media_files
    files += list_media_files(full_cur_file)
  File "/volume1/@appstore/sickbeard-custom/var/SickBeard/medusa/helpers/__init__.py", line 257, in list_media_files
    for cur_file in os.listdir(path):
  File "/volume1/@appstore/sickbeard-custom/var/SickBeard/medusa/init/filesystem.py", line 113, in patched_output
    return handle_output(f(*args, **kwargs))
  File "/volume1/@appstore/sickbeard-custom/var/SickBeard/medusa/init/filesystem.py", line 50, in _handle_output_u
    return list(map(_handle_output_u, result))
  File "/volume1/@appstore/sickbeard-custom/var/SickBeard/medusa/init/filesystem.py", line 47, in _handle_output_u
    return decode(result)
  File "/volume1/@appstore/sickbeard-custom/var/SickBeard/medusa/init/filesystem.py", line 32, in decode
    return text_type(value, 'utf-8' if os.name != 'nt' else fs_encoding)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x92 in position 26: invalid start byte

# Fixed code
def blocks_r(filename, size=64 * 1024, reset_offset=True, encoding="utf-8"):
    """
    Yields the data within a file in reverse-ordered blocks of given size.

    This code is part of the flyingcircus package: https://pypi.org/project/flyingcircus/
    The code was adapted for our use case.
    All credits go to the original author.

    Note that:
     - the content of the block is NOT reversed.

    Args:
        filename (str): The input file name.
        size (int|None): The block size.
            If int, the file is yielded in blocks of the specified size.
            If None, the file is yielded at once.
        reset_offset (bool): Reset the file offset.
            If True, starts reading from the end of the file.
            Otherwise, starts reading from where the file current position is.
        encoding (str|None): The encoding for correct block size computation.
            If `str`, must be a valid string encoding.
            If None, the default encoding is used.

    Yields:
        block (str): The data within the blocks.

    """
    with io.open(filename, "r", encoding=encoding) as file_obj:
        offset = 0
        if reset_offset:
            file_size = remaining_size = file_obj.seek(0, os.SEEK_END)
        else:
            file_size = remaining_size = file_obj.tell()
        rounding = 0
        while remaining_size > 0:
            offset = min(file_size, offset + size)
            file_obj.seek(file_size - offset)
            block = file_obj.read(min(remaining_size, size))
            remaining_size -= size
            yield block[: len(block) + rounding] if rounding else block