upsies.utils.release

Release name parsing and formatting

ReleaseInfo parses a string into a dictionary-like object with a specific set of keys, e.g. “title”, “resolution”, “source”, etc.

ReleaseName wraps ReleaseInfo to do the same, but in addition it tries to read media data from the file system to get information. It also adds a format method to turn everything back into a string.

Module Attributes

upsies.utils.release.DELIM = '[ \\.-]'

Regular expression that matches a single delimiter between release name parts, usually "." or " "

Classes

class upsies.utils.release.Episodes(*args, **kwargs)[source]

Bases: dict

dict subclass that maps season numbers to lists of episode numbers

All keys and values are str objects. All episodes from a season are indicated by an empty sequence. For episodes from any sason, the key is an empty string.

This class accepts the same arguments as dict.

To provide seasons as keyword arguments, you need to prefix “S” to each keyword. This is because numbers can’t be keyword arguments, but it also looks nicer.

>>> e = Episodes({"1": ["1", "2", "3"], "2": []})
>>> e.update(S01=[3, "4"], S3=range(2, 4), s05=[], S=[10, "E11", 12])
>>> e
>>> Episodes({'1': ['1', '2', '3', '4'], '2': [], '3': ['2', '3'], '5': [], '': ['10', '11', '12']})
regex = re.compile('(?:[ \\.-]|^)((?i:[SE]\\d+)+)(?:[ \\.-]|$)')

Regular expression that matches “S01E02”-like episode information

classmethod has_episodes_info(string)[source]

Whether string contains “S01E02”-like episode information

classmethod is_episodes_info(string)[source]

Whether string is “S01E02”-like episode information and nothing else

classmethod from_string(value)[source]

Create instance from release name or string that contains “Sxx” and “Exx”

Examples:

>>> Episodes.from_string('foo.E01 bar')
{'': ('1',)}
>>> Episodes.from_string('foo E01E2.bar')
{'': ('1', '2')}
>>> Episodes.from_string('foo.bar.E01E2S03')
{'': ('1', '2'), '3': ()}
>>> Episodes.from_string('E01E2S03E04E05.baz')
{'': ('1', '2'), '3': ('4', '5')}
>>> Episodes.from_string('S09E08S03E06S9E1')
{'9': ('1', '8',), '3': ('6',)}
>>> Episodes.from_string('E01S03E06.bar.E02')
{'': ('1', '2',), '3': ('6',)}
classmethod from_sequence(sequence)[source]

Combine episode information from multiple strings

Examples:

>>> Episodes.from_sequence(['foo.S01E01.bar', 'hello'])
{'1': ('1',)}
>>> Episodes.from_sequence(['foo.S01E01.bar', 'bar.S01E02.baz'])
{'1': ('1', '2')}
property is_season

Whether no episodes are specified, only complete seasons

Note

If no seasons and not episodes are specified, return False.

update(*args, clear=False, **kwargs)[source]

Set specific episodes from specific seasons, remove all other episodes and seasons

Params bool clear:

Whether to remove all seasons and episodes first

remove_specific_episodes()[source]

Remove episodes from each season, leaving only complete seasons

class upsies.utils.release.ReleaseInfo(path, *, strict=False)[source]

Bases: MutableMapping

Parse information from release name or path

Note

Consider using ReleaseName instead to get more accurate info from the data of existing files.

Parameters:
  • release (str) – Release name or path to release content

  • strict (bool) – Whether to raise ContentError if release looks bad, e.g. an abbreviated scene release file name like “tf-foof.mkv”

If release looks like an abbreviated scene file name (e.g. “abd-mother.mkv”), the parent directory’s name is used if possible.

Gathered information is provided as a dictionary with the following keys:

  • type (ReleaseType enum)

  • title

  • aka (Also Known As; anything after “AKA” in the title)

  • country

  • year

  • episodes (Episodes instance)

  • episode_title

  • date

  • edition (list of “Extended”, “Uncut”, etc)

  • resolution

  • service (Streaming service abbreviation)

  • source (“BluRay”, “WEB-DL”, etc)

  • audio_codec (Audio codec abbreviation)

  • audio_channels (e.g. “2.0” or “7.1”)

  • hdr_format

  • video_codec

  • group

  • has_commentary (bool or None to autodetect)

Unless documented otherwise above, all values are strings. Unknown values are empty strings.

copy()[source]

Return instance copy

property path

path argument as str

property release_name_params

Release name without title and year or season/episode info

This allows us to find stuff in the release name that guessit doesn’t support without accidentally finding it in the title.

class upsies.utils.release.ReleaseName(path, *, name=None, translate=None, separator=None, english_title_before_original=False)[source]

Bases: Mapping

Standardized release name

Parameters:
  • path (str) –

    Path to release file or directory

    If path exists, it is used to read video and audio metadata, e.g. to detect the codecs, resolution, etc.

  • name (str) – Path or other string to pass to ReleaseInfo (defaults to path)

  • translate (dict) –

    Map names of properties that return a string (e.g. audio_format) to maps of regular expressions to replacement strings. The replacement strings may contain backreferences to groups in their regular expression.

    Example:

    >>> {
    >>>     'audio_format': {
    >>>         re.compile(r'^DDP$'): r'DD+',
    >>>     },
    >>>     'video_format': {
    >>>         re.compile(r'^x26([45])$'): r'H.26\1',
    >>>     },
    >>> }
    

  • separator (str) – Separator between release name parts (usually “ “ or “.”) or None to use the default

Example:

>>> rn = ReleaseName("path/to/The.Foo.1984.1080p.Blu-ray.X264-ASDF")
>>> rn.source
'BluRay'
>>> rn.format()
'The Foo 1984 1080p BluRay DTS x264-ASDF'
>>> "{title} ({year}) [{group}]".format(**rn)
'The Foo (1984) [ASDF]'
>>> rn.set_name('The Foo 1985 1080p BluRay DTS x264-AsdF')
>>> "{title} ({year}) [{group}]".format(**rn)
'The Foo (1985) [AsdF]'
property release_info

Internal ReleaseInfo instance

set_release_info(path)[source]

Update internal ReleaseInfo instance

Parameters:

path – Argument for ReleaseInfo (path or any other string)

property path

str version of the path instantiation argument

property separator

Separator between release name parts (usually “ “ or “.”) or None to use the default

property type

ReleaseType enum or one of its value names

See also fetch_info().

title[source]

Original name of movie or series or “UNKNOWN_TITLE”

See also fetch_info().

title_aka[source]

Alternative name of movie or series or empty string

For non-English original titles, this should be the English title. If title is identical, this is an empty string.

See also fetch_info().

property english_title_before_original

Whether the English title is left of “AKA” and the original title is right of “AKA” in title_with_aka

If there is no title_aka, this has no effect.

title_with_aka[source]

Combination of title and title_aka

See also english_title_before_original.

title_with_aka_and_year[source]

Combination of title_with_aka with country and year if appropriate

If date is specified, it is appended to title_with_aka. Otherwise, if year_required is True, year is appended.

If country_required is True, country is appended.

In summary: This should provide a unique identifier for humans.

year[source]

Release year or “UNKNOWN_YEAR” if year_required is set, empty string otherwise

See also fetch_info().

property year_required

Whether title_with_aka_and_year includes year

See also fetch_info().

country[source]

Release country or “UNKNOWN_COUNTRY” if country_required is set, empty string otherwise

See also fetch_info().

property country_required

Whether title_with_aka_and_year includes country

See also fetch_info().

episodes[source]

Season and episodes in “S01E02”-style format or “UNKNOWN_SEASON” for season packs, “UNKNOWN_EPISODE” for episodes, empty string for other types

This property can be set to one or more season numbers (str, int or sequence of those), a “S01E02”-style string (see Episodes.from_string()) or any falsy value.

property episodes_dict

Episodes as Episodes object

property only_season

Season if there is only one season in episodes_dict, None otherwise

episode_title[source]

Episode title if type is “episode” or empty string

date[source]

Date (YYYY-MM-DD)

Sometimes single episodes are not released as part of a season but with an air date to identify them.

For episodes, this should be the air date or an empty string.

For anything that isn’t an episode, this is always an empty string.

service[source]

Streaming service abbreviation (e.g. “AMZN”, “NF”) or empty string

edition[source]

List of “Director’s Cut”, “Uncut”, “Unrated”, etc

Raises:

ContentError – if path exists but contains unexpected data

source[source]

Original source (e.g. “BluRay”, “WEB-DL”) or “UNKNOWN_SOURCE”

resolution[source]

Resolution (e.g. “1080p”) or “UNKNOWN_RESOLUTION”

Raises:

ContentError – if path exists but contains unexpected data

property resolution_int

Same as resolution, but as int or None if it cannot be determined

audio_format[source]

Audio format (e.g. “FLAC”) or empty string (no audio track) or “UNKNOWN_AUDIO_FORMAT”

Raises:

ContentError – if path exists but contains unexpected data

audio_channels[source]

Audio channels (e.g. “5.1”) or empty string (no audio track)

Raises:

ContentError – if path exists but contains unexpected data

hdr_format[source]

HDR format name (e.g. “DV” or “HDR10”) or empty string

If not set explicitly and path exists, this value is autodetected if possible, otherwise default to whatever ReleaseInfo detected in the release name.

Setting this value back to None turns on autodetection as described above.

Raises:

ContentError – if path exists but contains unexpected data

video_format[source]

Video format (or encoder in case of x264/x265/XviD) or “UNKNOWN_VIDEO_FORMAT”

Raises:

ContentError – if path exists but contains unexpected data

container[source]

Container format or “UNKNOWN_CONTAINER_FORMAT”

See get_container_format`() for possible return values.

Raises:

ContentError – if path exists but contains unexpected data

group[source]

Name of release group or “NOGROUP”

“NOGRP”, and “” are translated to “NOGROUP” case-insensitively.

property has_commentary

Whether this release has a commentary audio track

If not set explicitly and :attr:`path` exists, this value is autodetected by looking for “commentary” case-insensitively in any audio track title.

If not set explicitly and path does not exists, default to detection by ReleaseInfo.

Setting this value to None turns on autodetection as described above.

Raises:

ContentError – if path exists but contains unexpected data

property has_dual_audio

Whether this release has an English and a non-English audio track

If not set explicitly and path exists, this value is autodetected if possible, otherwise default to whatever ReleaseInfo detected in the release name.

Setting this value back to None turns on autodetection as described above.

Raises:

ContentError – if path exists but contains unexpected data

property dvd_resolution

“PAL” or “NTSC” for DVD release or None for non-DVD release

property is_complete

Whether all needed information is known and the string returned by format() will not contain “UNKNOWN_*”

This always returns False if type is unknown.

async fetch_info(*, webdb, webdb_id, callback=None)[source]

Fill in information web database

Parameters:
  • webdbWebDbApiBase instance (see webdb)

  • webdb_id (str) – Valid ID for webdb

  • callback (callable) – Function to call after info was fetched; gets the instance (self) as a keyword argument

Attempt to set these attributes if they are supported by webdb:

Returns:

The method’s instance (self) for convenience

format(separator=None)[source]

Assemble all parts into string

Parameters:

separator

Separator to use instead of space

The typical use case would be ..