Skip to main content

PlayOn facilities, primarily access to the download API. Includes a nice command line tool.

Short summary:

  • Feature: A PlayOn featured show record.

  • main: Playon command line mode; see the PlayOnCommand class below.

  • PlayOnAPI: Access to the PlayOn API.

  • PlayOnCommand: Playon command line implementation.

  • PlayOnSQLTags: PlayOn flavoured SQLTags; it just has custom values for the default db location.

  • Recording: A PlayOn recording.

  • Service: A PlayOn service description.

Functions

main(argv=None)

Playon command line mode; see the PlayOnCommand class below.

Classes

class Feature(_PlayOnEntity)

A PlayOn featured show record. I think.

Feature.TYPE_SUBNAME

'feature'

Feature.format_attributes

{'json': <function Entity.json at 0x10dd48400>}

class PlayOn(cs.tagged.Entities, cs.obj.Refreshable)

PlayOn.TYPE_CONVERSIONS

{   <class 'cs.app.playon.Recording'>: {   'Episode': <class 'int'>,
                                           'ReleaseYear': <class 'int'>,
                                           'Season': <class 'int'>}}

PlayOn.TYPE_ZONE

'playon'

PlayOn.__getitem__(self, index: tuple | int) -> cs.tagged.Entity

If index is an int return the associated Recording. Otherwise index should be a tuple, returns the associated Entity.

PlayOn.__iter__(self) -> Iterable[cs.app.playon.Recording]

Iteration iterates over the recordins.

PlayOn.all_recordings(self) -> Iterable[cs.app.playon.Recording]

A generator yielding all the Recordings from the database. Note that this includes both recorded, queued, and expired items.

PlayOn.features(self) -> set[cs.app.playon.Feature]

Return a set of Features known to the API.

PlayOn.ls(self, recording_specs, *, format: str, long_mode=False)

List the specified recordings.

PlayOn.queue(self) -> set[cs.app.playon.Recording]

Return a set of Recordings in the queue.

PlayOn.recording_ids_from_str(self, arg)

Convert a string to a list of recording ids.

PlayOn.recordings(self) -> set[cs.app.playon.Recording]

Return a set of Recordings known to the API.

PlayOn.services(self) -> set[cs.app.playon.Service]

Return a set of Services known to the API.

class PlayOnAPI(cs.obj.SingletonMixin, cs.service_api.HTTPServiceAPI)

Access to the PlayOn API.

PlayOnAPI.API_AUTH_GRACETIME

30

PlayOnAPI.API_BASE

'https://api.playonrecorder.com/v3/'

PlayOnAPI.API_HOSTNAME

'api.playonrecorder.com'

PlayOnAPI.CDS_BASE

'https://cds.playonrecorder.com/api/v6/'

PlayOnAPI.CDS_BASE_LOCAL

'https://cds-au.playonrecorder.com/api/v6/'

PlayOnAPI.CDS_HOSTNAME

'cds.playonrecorder.com'

PlayOnAPI.CDS_HOSTNAME_LOCAL

'cds-au.playonrecorder.com'

PlayOnAPI.PLAYON_ACCOUNT_ENVVAR

'PLAYON_ACCOUNT'

PlayOnAPI.__getitem__(self, index: tuple | int) -> cs.tagged.Entity

If index is an int return the associated Recording. Otherwise index should be a tuple, returns the associated Entity.

PlayOnAPI.account(self)

Return account information.

PlayOnAPI.auth_token

<property object at 0x11079aca0>

PlayOnAPI.cdsurl_data(self, suburl, method='GET', headers=None, **kw)

Wrapper for suburl_data using CDS_BASE as the base URL.

PlayOnAPI.default_user_id()

The default login_userid comes from the netrc entry for cls.API_HOSTNAME.

PlayOnAPI.download(self, download_id: int, filename=None, *, fstags: cs.fstags.FSTags, quiet: bool, runstate: Optional[cs.resources.RunState] = <function uses_runstate.<locals>.<lambda> at 0x1107ae2a0>, verbose: bool) -> tuple[str, dict]

Download the file with download_id to filename_basis. Return a 2-tuple of (saved,api_data) being the saved filesystem path and the data component of the API response.

The default filename is the basename of the filename from the download. If the filename is supplied with a trailing dot ('.') then the file extension will be taken from the filename of the download URL.

PlayOnAPI.featured_image_url(self, feature_name: str)

URL of the image for a featured show.

PlayOnAPI.features(self) -> list[dict]

Fetch the list of featured shows.

PlayOnAPI.from_playon_date(date_s) -> datetime.datetime

Return a timezone aware datetime from a PlayOn date/time value; The PlayOn API seems to use UTC date strings.

PlayOnAPI.login(self, login_subpath='login')

Perform a login, return the resulting dict. This does not update the state of self.*

The .login_state tracks the current auth state.

PlayOnAPI.notifications(self)

Return the notifications.

PlayOnAPI.queue(self) -> list[dict]

Return a list of the queued recording entries.

PlayOnAPI.recordings(self, *, verbose=False) -> list[dict]

Return a list of the available recording entries.

PlayOnAPI.renew_jwt(self)

UNUSED

PlayOnAPI.services(self) -> list[dict]

Fetch the list of services.

PlayOnAPI.suburl(self, suburl, *, api_version=None, headers=None, base_url=None, **kw)

Override HTTPServiceAPI.suburl with default headers={'Authorization':self.jwt}.

class PlayOnCommand(cs.cmdutils.BaseCommand)

Playon command line implementation.

Usage summary:

Usage: playon [common-options...] subcommand [args...]

  Environment:
    PLAYON_USER               PlayOn login name, default from $EMAIL.
    PLAYON_PASSWORD           PlayOn password.
                              This is obtained from .netrc if omitted.
    PLAYON_FILENAME_FORMAT  Format string for downloaded filenames.
                              Default: {series_prefix}{series_episode_name}--{resolution}--{playon.ProviderID}--playon--{playon.ID}
    PLAYON_TAGS_DBURL         Location of state tags database.
                              Default: ~/var/playon.sqlite

  Recording specification:
    an int        The specific recording id.
    all           All known recordings.
    downloaded    Recordings already downloaded.
    expired       Recording which are no longer available.
    pending       Recordings not already downloaded.
    /regexp       Recordings whose Series or Name match the regexp,
                  case insensitive.
  Subcommands:
    account [common-options...]
      Report account state.
    api [common-options...] suburl
      GET suburl via the API, print result.
    cds [common-options...] suburl
      GET suburl via the content delivery API, print result.
      Example subpaths:
        content
        content/provider-name
    dl [common-options...] [recordings...]
      Download the specified recordings, default "pending".
      Options:
        -j dl-jobs          Concurrent download jobs.
        -o filename-format  Filename format.
    downloaded [common-options...] recordings...
      Mark the specified recordings as downloaded and no longer pending.
    feature [common-options...] [feature_id]
      List features.
      Options:
        -l  Long mode.
    help [common-options...] [-l] [-s] [subcommand-names...]
      Print help for subcommands.
      This outputs the full help for the named subcommands,
      or the short help for all subcommands if no names are specified.
      Options:
        -l  Long listing.
        -r  Recurse into subcommands.
        -s  Short listing.
    info [common-options...] [field-names...]
      Recite general information.
      Explicit field names may be provided to override the default listing.
    ls [common-options...] [recordings...]
      List available downloads.
      Options:
        -l            Long listing: list tags below each entry.
        -o ls-format  Format string for each entry. Default format:
                      {playon.ID} {playon.HumanSize} {resolution} {nice_name} {playon.ProviderID} {status:upper}
    poll [common-options...] [options...]
    q [common-options...] [recordings...]
      List queued recordings.
      Options:
        -l               Long listing: list tags below each entry.
        -o queue-format  Format string for each entry. Default format:
                         {playon.ID} {playon.Series} {playon.Name} {playon.ProviderID}
    queue [common-options...] [recordings...]
      List queued recordings.
      Options:
        -l               Long listing: list tags below each entry.
        -o queue-format  Format string for each entry. Default format:
                         {playon.ID} {playon.Series} {playon.Name} {playon.ProviderID}
    refresh [common-options...]
      Update the db state from the PlayOn service.
    rename [common-options...] [-o filename_format] filenames...
      Rename the filenames according to their fstags.
      -n    No action, dry run.
      -o filename_format
            Format for the new filename, default '{series_prefix}{series_episode_name}--{resolution}--{playon.ProviderID}--playon--{playon.ID}'.
      Options:
        -o filename-format  Filename format.
    repl [common-options...]
      Run a REPL (Read Evaluate Print Loop), an interactive Python prompt.
      Options:
        --banner banner  Banner.
    service [common-options...] [service_id]
      List services.
    shell [common-options...]
      Run a command prompt via cmd.Cmd using this command's subcommands.

PlayOnCommand.Options(cmd: Optional[str] = None, dry_run: bool = False, force: bool = False, verbosity: int = 0, runstate: Optional[cs.resources.RunState] = None, runstate_signals: Tuple[int] = (<Signals.SIGHUP: 1>, <Signals.SIGINT: 2>, <Signals.SIGQUIT: 3>, <Signals.SIGTERM: 15>), ssh_exe: str = <factory>, user: Optional[str] = <factory>, password: Optional[str] = <factory>, dl_jobs: int = 2, filename_format: str = <factory>, ls_format: str = '{playon.ID} {playon.HumanSize} {resolution} {nice_name} {playon.ProviderID} {status:upper}', queue_format: str = '{playon.ID} {playon.Series} {playon.Name} {playon.ProviderID}') -> None

Options(cmd: Optional[str] = None, dry_run: bool = False, force: bool = False, verbosity: int = 0, runstate: Optional[cs.resources.RunState] = None, runstate_signals: Tuple[int] = (<Signals.SIGHUP: 1>, <Signals.SIGINT: 2>, <Signals.SIGQUIT: 3>, <Signals.SIGTERM: 15>), ssh_exe: str = , user: Optional[str] = , password: Optional[str] = , dl_jobs: int = 2, filename_format: str = , ls_format: str = '{playon.ID} {playon.HumanSize} {resolution} {nice_name} {playon.ProviderID} {status:upper}', queue_format: str = '{playon.ID} {playon.Series} {playon.Name} {playon.ProviderID}')

PlayOnCommand.USAGE_FORMAT

('Usage: {cmd} subcommand [args...]\n'
 '\n'
 '    Environment:\n'
 '      PLAYON_USER               PlayOn login name, default from $EMAIL.\n'
 '      PLAYON_PASSWORD           PlayOn password.\n'
 '                                This is obtained from .netrc if omitted.\n'
 '      {FILENAME_FORMAT_ENVVAR}  Format string for downloaded filenames.\n'
 '                                Default: {DEFAULT_FILENAME_FORMAT}\n'
 '      {PLAYON_DBURL_ENVVAR:17}         Location of state tags database.\n'
 '                                Default: {PLAYON_DBURL_DEFAULT}\n'
 '\n'
 '    Recording specification:\n'
 '      an int        The specific recording id.\n'
 '      all           All known recordings.\n'
 '      downloaded    Recordings already downloaded.\n'
 '      expired       Recording which are no longer available.\n'
 '      pending       Recordings not already downloaded.\n'
 '      /regexp       Recordings whose Series or Name match the regexp,\n'
 '                    case insensitive.\n'
 '  ')

PlayOnCommand.USAGE_KEYWORDS

{   'DEFAULT_DL_PARALLELISM': 2,
    'DEFAULT_FILENAME_FORMAT': '{series_prefix}{series_episode_name}--{resolution}--{playon.ProviderID}--playon--{playon.ID}',
    'FILENAME_FORMAT_ENVVAR': 'PLAYON_FILENAME_FORMAT',
    'LS_FORMAT': '{playon.ID} {playon.HumanSize} {resolution} {nice_name} '
                 '{playon.ProviderID} {status:upper}',
    'PLAYON_DBURL_DEFAULT': '~/var/playon.sqlite',
    'PLAYON_DBURL_ENVVAR': 'PLAYON_TAGS_DBURL',
    'QUEUE_FORMAT': '{playon.ID} {playon.Series} {playon.Name} '
                    '{playon.ProviderID}'}

PlayOnCommand.cmd_account(self, argv)

Usage: {cmd} Report account state.

PlayOnCommand.cmd_api(self, argv)

Usage: {cmd} suburl GET suburl via the API, print result.

PlayOnCommand.cmd_cds(self, argv)

Usage: {cmd} suburl GET suburl via the content delivery API, print result. Example subpaths: content content/provider-name

PlayOnCommand.cmd_dl(self, argv)

Usage: {cmd} [recordings...] Download the specified recordings, default "pending". Options: -j dl-jobs Concurrent download jobs. -o filename-format Filename format.

PlayOnCommand.cmd_downloaded(self, argv, locale='en_US')

Usage: {cmd} recordings... Mark the specified recordings as downloaded and no longer pending.

PlayOnCommand.cmd_feature(self, argv, locale='en_US')

Usage: {cmd} [feature_id] List features. Options: -l Long mode.

PlayOnCommand.cmd_ls(self, argv)

Usage: {cmd} [recordings...] List available downloads. Options: -l Long listing: list tags below each entry. -o ls-format Format string for each entry. Default format: {LS_FORMAT}

PlayOnCommand.cmd_q(self, argv)

Usage: {cmd} [recordings...] List queued recordings. Options: -l Long listing: list tags below each entry. -o queue-format Format string for each entry. Default format: {QUEUE_FORMAT}

PlayOnCommand.cmd_queue(self, argv)

Usage: {cmd} [recordings...] List queued recordings. Options: -l Long listing: list tags below each entry. -o queue-format Format string for each entry. Default format: {QUEUE_FORMAT}

PlayOnCommand.cmd_refresh(self, argv)

Usage: {cmd} Update the db state from the PlayOn service.

PlayOnCommand.cmd_rename(*a, fstags: Optional[cs.fstags.FSTags] = <function uses_fstags.<locals>.<lambda> at 0x1107360c0>, **kw)

Usage: {cmd} [-o filename_format] filenames... Rename the filenames according to their fstags. -n No action, dry run. -o filename_format Format for the new filename, default {DEFAULT_FILENAME_FORMAT!r}. Options: -o filename-format Filename format.

PlayOnCommand.cmd_service(self, argv, locale='en_US')

Usage: {cmd} [service_id] List services.

PlayOnCommand.run_context(self)

Prepare the PlayOnAPI around each command invocation.

class PlayOnLoginState(cs.service_api.LoginState)

class PlayOnSQLTags(cs.sqltags.SQLTags)

PlayOn flavoured SQLTags; it just has custom values for the default db location.

PlayOnSQLTags.DBURL_DEFAULT

'~/var/playon.sqlite'

PlayOnSQLTags.DBURL_ENVVAR

'PLAYON_TAGS_DBURL'

class Recording(_PlayOnEntity)

A PlayOn recording.

Recording.RECORDING_QUALITY

{1: '720p', 2: '1080p'}

Recording.TYPE_SUBNAME

'recording'

Recording.as_SeriesEpisodeInfo(self) -> cs.mediainfo.SeriesEpisodeInfo

Infer series episode information from a Recording (or any mapping with "playon.*" keys).

Recording.download(self, filename: str, *, fstags: cs.fstags.FSTags, playon_api: cs.app.playon.PlayOnAPI, runstate: Optional[cs.resources.RunState] = <function uses_runstate.<locals>.<lambda> at 0x110734180>)

Download this recording to filename.

Recording.filename(self, filename_format=None) -> str

Return the computed filename per filename_format, default from DEFAULT_FILENAME_FORMAT: '{series_prefix}{series_episode_name}--{resolution}--{playon.ProviderID}--playon--{playon.ID}'.

Recording.format_attributes

{   'is_available': <function Recording.is_available at 0x1107afba0>,
    'is_downloaded': <function Recording.is_downloaded at 0x1107afce0>,
    'is_expired': <function Recording.is_expired at 0x1107afe20>,
    'is_pending': <function Recording.is_pending at 0x1107afd80>,
    'is_queued': <function Recording.is_queued at 0x1107afc40>,
    'json': <function Entity.json at 0x10dd48400>,
    'nice_name': <function Recording.nice_name at 0x1107af920>,
    'recording_id': <function Recording.recording_id at 0x1107af6a0>,
    'resolution': <function Recording.resolution at 0x1107af560>,
    'series_episode_name': <function Recording.series_episode_name at 0x1107afb00>,
    'series_prefix': <function Recording.series_prefix at 0x1107afa60>,
    'status': <function Recording.status at 0x1107af9c0>}

Recording.is_available(self)

Is a recording available for download?

Recording.is_downloaded(self)

Test whether this recording has been downloaded based on the presence of a download_path Tag or a true downloaded Tag.

Recording.is_expired(self)

Test whether this recording is expired, which implies that it is no longer available for download.

Recording.is_pending(self)

A pending download: available and not already downloaded.

Recording.is_queued(self)

Is a recording still in the queue?

Recording.ls(self, *, format=None, long_mode=False, print_func=None)

List a recording.

Recording.nice_name(self)

A nice name for the recording: the PlayOn series and name, omitting the series if that is None.

Recording.recording_id(self)

The recording id or None.

Recording.refresh_lifespan

600

Recording.refresh_needed(self, **kw)

Override for Refreshable.refresh_needed which always returns False for expired recordings.

Recording.resolution(self)

The recording resolution derived from the quality via the Recording.RECORDING_QUALITY mapping.

Recording.sei

<functools.cached_property object at 0x11077f4d0>

Recording.series_prefix(self)

Return a series prefix for recording containing the series name and season and episode, or ''.

Recording.status(self)

Return a short status string.

class Service(_PlayOnEntity)

A PlayOn service description.

Service.TYPE_SUBNAME

'service'

Service.format_attributes

{'json': <function Entity.json at 0x10dd48400>}

Release files for cs-app-playon 20260914

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cs-app-playon 20260914
File Size Uploaded
cs_app_playon-20260914.tar.gz 18.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cs-app-playon 20260914
File Interpreter ABI Platform
cs_app_playon-20260914-py2.py3-none-any.whl Python 3, Python 2 none any Details

Total release size: 35.9 kB

Release files / cs_app_playon-20260914.tar.gz

Download URL cs_app_playon-20260914.tar.gz
Size 18.8 kB
Tags Source
SHA-256 checksum
How to use checksums
d1dd2a1a17835d52a4bbd6814dc65d0fb10e4e8262cb0542cec3142f2a248bd4
BLAKE2b-256 checksum
How to use checksums
b12cc35b83d62a5c216e465dd48e7387ab8d0f0c69d1f9573c81dfbc50c7a2d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.1

Release files / cs_app_playon-20260914-py2.py3-none-any.whl

Download URL cs_app_playon-20260914-py2.py3-none-any.whl
Size 17.1 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
bc2a60b9b846706715b60ab250ba28631b71fd34572b3284a079b3c9a903ace5
BLAKE2b-256 checksum
How to use checksums
235660cb3575462328e76dec38f2a41a976531de82aa669b946449b4f755730c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.1
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page