Skip to content

Commit

Permalink
Remove set_verbosity_level(), set_cracking_mode(), and related code
Browse files Browse the repository at this point in the history
It is not actually possible to set the environment variable from python in such a way for the library to get the changes. I've tried manipulating os.environ, setx, py-setenv, and pycrosskit.

Nothing set it persistently for the current terminal/shell in such a way that it could be changed at a whim by these methods. The closest result was setx but it required the entire terminal/shell to reload, making it more or less useless in this context.
  • Loading branch information
rlaphoenix committed Jul 20, 2024
1 parent da7e99e commit a530c81
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 123 deletions.
24 changes: 8 additions & 16 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ up with the latest versions of other dependencies as well as crucial bug fixes.
### Fixed

- Various CI and linting tooling mistakes and made it more efficient.
- Fixed unsetting of verbosity and cracking modes on Windows systems by requiring
Python 3.9 or newer as the `os.unsetenv` function only existed on other operating
systems before then.
- Fixed value comparison used when unsetting cracking mode to "unset" string, not
`-1` integer.

### Changed

Expand All @@ -30,7 +25,6 @@ up with the latest versions of other dependencies as well as crucial bug fixes.
- The base exception `PyDvdCssException` was renamed to `PyDvdCssError`.
- The exception `LibDvdCssNotFound` was renamed to `LibraryNotFoundError`.
- `DvdCss.close()` now only returns True if a device was actually closed when called.
- `DvdCss.set_verbosity()` has been renamed to `DvdCss.set_verbosity_level()`.
- `DvdCss.error()` is now a property, via `@property` decorator.
- `DvdCss.error` will now return None if no DVD device or directory was opened yet.
- `DvdCss.error` may now return None if there is no error string to return, or if
Expand All @@ -44,17 +38,10 @@ up with the latest versions of other dependencies as well as crucial bug fixes.
`flag`.
- `DvdCss.read()` changed parameter names from `i_blocks` to `sectors` and `i_flags` to
`flag`.
- `DvdCss.set_verbosity_level()` changed parameter names from `verbosity` to `level`.
- `DvdCss.seek()` now uses a `SeekFlag` enum for the `flag` parameter instead of an
integer value. However, you can still use an int if you prefer.
- `DvdCss.read()` now uses a `ReadFlag` enum for the `flag` parameter instead of an
integer value. However, you can still use an int if you prefer.
- `DvdCss.set_verbosity_level()` now uses a `VerbosityLevel` enum for the `level` parameter
and return value instead of an integer value. However, you can still pass an int if
you prefer.
- `DvdCss.set_cracking_mode()` now uses a `CrackingMode` enum for the `mode` parameter
and return value instead of a string value. However, you can still pass a string if
you prefer.
- `DvdCss.open()` and `DvdCss.open_stream()` now raises an `AlreadyInUseError` exception
instead of a `ValueError` when you try to open a 2nd disc in the same class instance.
- `DvdCss.open()` and `DvdCss.open_stream()` now raises an `OpenFailureError` exception
Expand All @@ -71,16 +58,21 @@ up with the latest versions of other dependencies as well as crucial bug fixes.
failure to close an open device or directory.
- `DvdCss.dispose()` is now deprecated and an alias of `DvdCss.close()` and no longer
unsets the verbosity level or cracking mode environment variables. This is because
this is set in your environment, not per-instance. Its not logical to reset it when
it will affect every other instance running. Instead, pay close attention to your
instances and handle resetting the level/mode yourself.
it cant actually work (see Removed section), and even if it did it is set in your
environment, not per-instance. Its not logical to reset it when it will affect every
other instance running.
- The list of possible library names were put into constants as `LIBRARY_NAMES`.

### Removed

- The `SECTOR_SIZE`, `BLOCK_BUFFER`, `NO_FLAGS`, `READ_DECRYPT`, `SEEK_MPEG`,
`SEEK_KEY`, `flags_m`, and `flags_s` class variables were removed. The variables to
do with flags/read/seek were refactored as SeekFlag and ReadFlag.
- The `DvdCss.set_verbosity()` and `DvdCss.set_cracking_mode()` methods as it is not
actually possible to set the environment variable from Python in such a way for the
library to see the changes. I've tried manipulating os.environ, setx, py-setenv, and
pycrosskit. Nothing set it persistently for the current terminal/shell in such a way
without needing the terminal/shell to reload, making this method pointless.

## [1.4.0] - 2023-10-12

Expand Down
105 changes: 33 additions & 72 deletions pydvdcss/dvdcss.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import os
from ctypes import (
CDLL,
c_char_p,
Expand All @@ -16,11 +15,9 @@

from pydvdcss import constants, exceptions, types
from pydvdcss.structs import (
CrackingMode,
DvdCssStreamCb,
ReadFlag,
SeekFlag,
VerbosityLevel,
)
from pydvdcss.utilities import message_with_error

Expand All @@ -34,11 +31,40 @@ class DvdCss:
VLC, a full video client/server streaming solution. VLC can also be used as a
standalone program to play video streams from a hard disk or a DVD.
The Environment Variables `DVDCSS_METHOD` and `DVDCSS_VERBOSE` are handled by
:func:`set_cracking_mode` and :func:`set_verbosity_level` respectively. See those
functions for more information.
libdvdcss is copyright of VideoLAN and licensed under GNU General Public License.
Some environment variables can be used to change the behavior of libdvdcss:
Environment Variables:
DVDCSS_VERBOSE: Sets the verbosity level.
- 0 outputs no messages at all.
- 1 outputs error messages to stderr.
- 2 outputs error messages and debug messages to stderr.
DVDCSS_METHOD: Sets the authentication & decryption method to descramble discs.
- key is the default method. libdvdcss will use a set of calculated player keys
to try and get the disc key. This can fail if the drive does not recognize any
of the player keys.
- disc is a fallback method when key has failed. Instead of using player keys,
libdvdcss will crack the disc key using a brute force algorithm. This process
is CPU intensive and requires 64 MB of memory to store temporary data.
- title is the fallback when all other methods have failed. It does not rely on
a key exchange with the DVD drive, but rather uses a crypto attack to guess
the title key. In rare cases this may fail because there is not enough
encrypted data on the disc to perform a statistical attack, but on the other
hand it is the only way to decrypt a DVD stored on a hard disc, or a DVD with
the wrong region on an RPC2 drive.
DVDCSS_RAW_DEVICE: Specify the raw device to use. Exact usage will depend on
your operating system, the Linux utility to set up raw devices is raw(8) for
instance. Please note that on most operating systems, using a raw device
requires highly aligned buffers: Linux requires a 2048 bytes alignment (which
is the size of a DVD sector).
DVDCSS_CACHE: Specify a directory in which to cache title key values. This will
speed up descrambling of DVDs which are in the cache. The DVDCSS_CACHE directory
is created if it does not exist, and a subdirectory is created named after the
DVD's title or manufacturing date. If DVDCSS_CACHE is not set or is empty,
libdvdcss will use the default value which is "${HOME}/.dvdcss/" under Unix and
"C:/Documents and Settings/$USER/Application Data/dvdcss/" under Win32. The
special value "off" disables caching.
"""

def __init__(self) -> None:
Expand Down Expand Up @@ -300,71 +326,6 @@ def is_scrambled(self) -> bool:
return False
return self._library.dvdcss_is_scrambled(self.handle) == 1

@staticmethod
def set_verbosity_level(
level: types.VerbosityLevel_T = VerbosityLevel.Nothing,
) -> VerbosityLevel:
"""
Set libdvdcss verbosity (DVDCSS_VERBOSE environment variable).
Parameters:
level:
- Unset (-1): Unset the DVDCSS_VERBOSE environment variable.
Verbosity used will be up to the discretion of the library.
- Info ( 0): Outputs no messages at all.
- Error ( 1): Outputs error messages to stderr.
- Debug ( 2): Outputs error messages and debug messages to stderr.
Returns the newly set verbosity level.
"""
if isinstance(level, int):
level = VerbosityLevel(level)
elif not isinstance(level, VerbosityLevel):
raise TypeError(f"Expected an int or VerbosityLevel enum, not {level!r}")

if level == VerbosityLevel.Unset:
os.unsetenv("DVDCSS_VERBOSE")
else:
os.environ["DVDCSS_VERBOSE"] = str(level.value)

return VerbosityLevel(int(os.environ.get("DVDCSS_VERBOSE", -1)))

@staticmethod
def set_cracking_mode(
mode: types.CrackingMode_T = CrackingMode.Key,
) -> CrackingMode:
"""
Set libdvdcss cracking mode (DVDCSS_METHOD environment variable).
Parameters:
mode:
- Unset ("unset"): Unset the DVDCSS_METHOD environment variable.
- Title ("title"): By default the decrypted title key is guessed
from the encrypted sectors of the stream. Thus it should work with a
file as well as the DVD device. But decrypting a title key may take
too much time or even fail. With the title method, the key is only
checked at the beginning of each title, so it will not work if the
key changes in the middle of a title.
- Disc ("disc"): The disc key is cracked first. Afterwards all title
keys can be decrypted instantly, which allows checking them often.
- Key ("key"): The same as the "disc" method if you do not have a file
with player keys at compile time. If you do, disc key decryption will
be faster. This is the default method also employed by libdvdcss.
Returns the newly set cracking method.
"""
if isinstance(mode, str):
mode = CrackingMode(mode)
elif not isinstance(mode, CrackingMode):
raise TypeError(f"Expected a str or CrackingMode enum, not {mode!r}")

if mode == CrackingMode.Unset:
os.unsetenv("DVDCSS_METHOD")
else:
os.environ["DVDCSS_METHOD"] = mode.value

return CrackingMode(os.environ.get("DVDCSS_METHOD", "unset"))

@staticmethod
def _load_library() -> CDLL:
"""Load libdvdcss DLL/SO library via ctypes CDLL if available."""
Expand Down
32 changes: 1 addition & 31 deletions pydvdcss/structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,6 @@
from enum import Enum


class VerbosityLevel(Enum):
Unset = -1
"""Unset the DVDCSS_VERBOSE environment variable."""
Nothing = 0
"""Outputs no messages at all."""
Error = 1
"""Outputs error messages to stderr."""
Debug = 2
"""Outputs error messages and debug messages to stderr."""


class CrackingMode(Enum):
Unset = "unset"
"""Unset the DVDCSS_METHOD environment variable."""
Title = "title"
"""By default the decrypted title key is guessed from the encrypted
sectors of the stream. Thus it should work with a file as well as
the DVD device. But decrypting a title key may take too much time
or even fail. With the title method, the key is only checked at
the beginning of each title, so it will not work if the key
changes in the middle of a title."""
Disc = "disc"
"""The disc key is cracked first. Afterwards all title keys can be
decrypted instantly, which allows checking them often."""
Key = "key"
"""The same as the "disc" method if you do not have a file with player
keys at compile time. If you do, disc key decryption will be faster.
This is the default method also employed by libdvdcss."""


class SeekFlag(Enum):
Unset = 0
SEEK_MPEG = 1
Expand Down Expand Up @@ -63,4 +33,4 @@ class DvdCssStreamCb(Structure):
)


__all__ = ("VerbosityLevel", "CrackingMode", "SeekFlag", "ReadFlag", "DvdCssStreamCb")
__all__ = ("SeekFlag", "ReadFlag", "Iovec", "DvdCssStreamCb")
6 changes: 2 additions & 4 deletions pydvdcss/types.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from typing import Literal

from pydvdcss.structs import CrackingMode, ReadFlag, SeekFlag, VerbosityLevel
from pydvdcss.structs import ReadFlag, SeekFlag

VerbosityLevel_T = VerbosityLevel | Literal[-1, 0, 1, 2]
CrackingMode_T = CrackingMode | Literal["unset", "title", "disc", "key"]
SeekFlag_T = SeekFlag | Literal[0, 1, 2]
ReadFlag_T = ReadFlag | Literal[0, 1]

__all__ = ("VerbosityLevel_T", "CrackingMode_T", "SeekFlag_T", "ReadFlag_T")
__all__ = ("SeekFlag_T", "ReadFlag_T")

0 comments on commit a530c81

Please sign in to comment.