Skip to content

Writing a Meta player

metate edited this page Mar 17, 2016 · 14 revisions

Writing a Meta-player

A Meta-player is a json file with ".meta.json" file extension that specifies how to link an external addon, a local directory or your local library to Meta. A Meta-player can either specify a parameterized link to use for playing the media directly or specify the steps to use in order to browse through an external addon until list items that match the requested media are found. In this guide we will explain the format of a meta.json file, provide full examples and then provide a few guidelines that may make it easier for you to write a working Meta-player. Minimal familiarity with Python and JSON is recommended.

Tips:

  • Meta-players are located in the kodi/userdata/addon_data/plugin.video.meta/players folder
  • If you want to maintain a set of Meta-players online, create a GitHub repository with all Meta-players and use the following endpoint as the link to use in Meta's settings: https://api.github.com/repos/:owner/:repo/zipball
  • Official Meta-players are maintained Here. Feel free to submit a PR for any Meta-player for a legal addon.

Table of Contents

##Parameters

The hints in a Meta-player can use parameters provided by Meta according to the selected media itself. For example, {title} is the movie's name, {imdb} is the movie's IMDB identifier, etc.

Parameters are written inside curly brackets {}. Formatting is also supported, e.g.: {season:02d} is replaced with a 2-letters season number with a leading zero if needed. Note that escaping curly brackets, if you need it for any other purpose other than specifying parameters, is achieved by writing {{ and }}.

Text parameters also have siblings that determine how whitespaces are interpreted. Currently you can use _escaped for %2520 (equals to the encoded whitespace symbol %20 after unquoting), _escaped+ for %252B (equals to the encoded plus sign %2B after unquoting), _+ for plus and _- for dash. For example:

  • {title}: Awesome movie
  • {title_+}: Awesome+movie
  • {title_-}: Awesome-movie
  • {title_escaped}: Awesome%2520movie
  • {title_escaped+}: Awesome%252Bmovie

For other replacements you may apply functions to text parameters. Currently two functions are supported: 'ws' to replace whitespaces and 'replace' to replace any substring. The characters [ . : and ] must be escaped to &sbo; ˙ : and &sbc; respectively. Examples:

  • {title|ws(%2B)} will replace whitespaces with %2B (URL encoding for +)
  • {title|replace(˙,%20)} will replace dots with %20 (URL encoding for whitespsace)
  • {title|replace(˙, )|ws(%2520)} will replace dots with whitespaces and then whitespaces with %2520 (turns into %20 if the target addon calls urllib2.unquote on the parameter)

####Movie parameters:

  • id: TMDB id
  • imdb: IMDB id
  • trakt: Trakt id
  • slug: Trakt slug
  • title: Movie title
  • year: Movie release year
  • name: Formatted as "title (year)"

####TV show parameters:

  • id: TVDB id
  • imdb: IMDB id
  • tmdb: TMDB id
  • trakt: Trakt id
  • slug: Trakt slug
  • showname: Show name as listed in TVDB
  • clearname: Show name excluding year if present
  • name: Formatted as "{showname} S{season:02d}E{episode:02d}" or "{showname} {absolute_number}" for anime
  • title: Episode title
  • season: Season number
  • episode: Episode number
  • absolute_number: Absolute episode number
  • firstaired: First aired date (yyyy-mm-dd)
  • year: First aired year
  • network: Broadcast network
  • network_clear: Broadcast network without country code (e.g., "ABC (US)" -> "ABC")
  • genre: Genre as listed in TMDB

####More parameters: Additional parameters can be accessed through the `info' parameter. Documentation is missing because these parameters can usually be omitted. For now I'll give a few examples:

  • {info[plot]}
  • {info[genre]}
  • {info[rating]}
  • {info[votes]}
  • {info[poster]}
  • {info[fanart]}

##Meta-player format

Root: dictionary

    "name": string
        Display name (HTML tags allowed)

    "plugin": string [optional]
        Ignore player if a plugin with the id of the sepecified value is not
        installed.
        
    "id": string [optional, default=from file name]
        Unique string identifier. As convention please use: 
        "provider.{your_name}.{addon_name}"

    "filters": dictionary [optional]
        Ignore player if filters don't match.
        Currently only "network" filter for tvshows is supported.
        Example: {"network": "BBC"}.

    "postprocess": string [optional]
        Restricted python code (imports, modules and builtins are disallowed).
        The code should only be used to modify found links. Use the variable "link" to refer to the link to modify. 
        Example: "link.replace('demo=1','demo=0')"
        
    "movies": list<CommandSequence> [optional]
        List of CommandSequence entries for playing a movie video.
        Meta executes all CommandSequence entries (one at the time).
                        
    "tvshows": list<CommandSequence> [optional]
        List of CommandSequence entries for playing an episode.
        Meta executes all CommandSequence entries (one at the time).

CommandSequence: list<CommandItem>

    List of CommandItem entries.
    Meta stops executing a CommandSequence at the first successful CommandItem.

CommandItem: dict

    "action": string [optional, default="PLAY"]
        PLAY:  Use it if final URL is video.
        ACTIVATE: Use it if final URL is a folder or a custom view.

    "language": string [optional, default="en"]
        Language to use for parameters.
        
    "link": string
        A parameterized URL.
        
        If URL is final then the "steps" item should be omitted.
        Example: 
            [*] plugin://plugin.video.example/{imdb}/play
            
        If browsing list items is needed then a "plugin://" URL should be used
        as a starting point for external browsing.
        Examples:
            [*] plugin://plugin.video.example/?action=search&q={title}
            [*] plugin://plugin.video.example/all/
            [*] plugin://plugin.video.example

    "steps": list<string> [optional]
        List of parameterized hints to specify how to browse the external addon or folder. 
        For example if plugin.video.example provides a list of public
        domain movies in its root, and after selecting a movie the user needs
        to select one of two list items: "play movie" or "play trailer" then
        the steps to use are: ["{title}", "play movie"].

        There are 3 types of steps are available:
            [*] **Regex** - Regular expression steps are used by default. 
                Please see common regex symbols below if you are unfamiliar with regex. 
                The matching is done by comparing the text in the addon to the step's regex. 
                Before comparing, the following symbols are replaced with white-space in
                both the text from the addon and parameters: ., %20.  
            [*] **Info** - Some addons specify season and episode number as an info label
                instead of the list item label. The {season}, {episode} and {season}x{episode} 
                steps are specifically designed to match not only against the list item label
                but also against info labels. if you don't know if an addon sets the
                info-labels, you can see it in `Media info' view of confluence (it would show
                "Episode: SxE" on the right panel if the info-labels are set).
            [*] **Keyboard** - Keyboard steps are used to send text to the virtual keyboard.
                Continuing the previous example, if plugin.video.example has a Search item
                that opens the keyboard to search for a movie then the steps to use are:
                ["Search", "keyboard: {title}", "{title}", "play movie"]. Note that a
                keyboard step can never be the last in a steps list. 

        Common regex symbols:
        .   - Any character.
        *   - Previous character/group can appear zero or many times.
        +   - Previous character/group can appear one or more times.
        ?   - Previous character/group is optional.
        .*  - Match anything (greedy).
        .*? - Match anything (not greedy).
        $$  - Match start of string or end of string or white-space or [ or ].
              Note: not a standard regex but we have added it for convenience.

##Full examples

Filename: provider.library.meta.json

Description: Search media in Kodi's library.

{
    "name": "Library",
    "tvshows": [
        [
            {
                "link": "tvshows"
            }
        ]
    ],
    "movies": [
        [
            {
                "link": "movies"
            }
        ]
    ]
}

Filename: provider.local.meta.json

Description: Search episode in a local folder. The folder must be configured in Kodi's file explorer.

{
    "id": "provider.local",
    "name": "Local",
    "tvshows": [
        [
            {
                "link": "c:/Videos/",
                "steps": [
                    "{clearname}.*S{season:02d}E{episode:02d}.*(avi|mp4)"
                ]
            }
        ]
    ]
}

Filename: provider.quasar.meta.json

Description: Play using plugin.video.quasar.

{
    "plugin": "plugin.video.quasar",
    "name": "Quasar",
    "movies": [
        [
            {
                "link": "plugin://plugin.video.quasar/movie/{tmdb}/play"
            }
        ]
    ],
    "tvshows": [
        [
            {
                "link": "plugin://plugin.video.quasar/show/{tmdb}/season/{season}/episode/{episode}/play"
            }
        ]
    ]
}

Filename: provider.flix2kodi.meta.json

Description: Search using flix2kodi. This player shows how to use a keyboard step. Keep in mind that if you can avoid using keyboard steps please do.

{
    "name": "Netflix",
    "plugin": "plugin.video.flix2kodi",
    "priority": 500,
    "movies": [
        [
            {
                "link": "plugin://plugin.video.flix2kodi/?mode=search&thumb&type=movie&url",
                "steps": [
                    "keyboard: {title}",
                    "{title}.*"
                ]
            }
        ]
    ],
    "tvshows": [
        [
            {
                "link": "plugin://plugin.video.flix2kodi/?mode=search&thumb&type=show&url",
                "steps": [
                    "keyboard: {showname}",
                    ".*{showname}.*",
                    ".*Season {season}",
                    "{episode}"
                ]
            }
        ]
    ]
}

Filename: provider.iba.meta.json

Description: Search episodes in plugin.video.IBA. The IBA addon is written in Hebrew so the Meta-player below will not really work and is only here to show the syntax. A working Meta-player in Hebrew is added right below it for users that are familiar with Hebrew.

{
    "name": "IBA",
    "plugin": "plugin.video.IBA",
    "filters": {
        "network": "channel one"
    },
    "tvshows": [
        [
            {
                "language": "he",
                "link": "plugin://plugin.video.IBA/",
                "steps": [
                    "{showname}",
                    ".*Season {season}",
                    "(?:{showname}|Full episodes)",
                    ".*Episode {episode}"
                ]
            }
        ]
    ]
}

Hebrew version (this one really works with the IBA addon):

{
    "name": "IBA",
    "plugin": "plugin.video.IBA",
    "filters": {
        "network": "הערוץ הראשון"
    },
    "tvshows": [
        [
            {
                "language": "he",
                "link": "plugin://plugin.video.IBA/",
                "steps": [
                    "{showname}",
                    ".*עונה {season}",
                    "(?:{showname}|פרקים מלאים)",
                    ".*פרק {episode}"
                ]
            }
        ]
    ]
}

##Tips and Tricks We will now show three methods that may be used to write a CommandSequence. We will add support for a (dummy) plugin that has the id plugin.video.example.

####Browsing an external addon

Say the addon lists all movies in english inside Movies->All and after choosing a movie it shows (not in a dialog) a few links in the a "[Quality] name" format.

Here is the CommandSequence to use for adding support for this addon, prefering 720P first and falling back to any quality otherwise:

[
 {
  "link": "plugin://plugin.video.example",
  "steps": ["Movies", "All", "{title}", "\[720p\].*"]
 },
 {
  "link": "plugin://plugin.video.example",
  "steps": ["Movies", "All", "{title}", ".*"]
 }     
]

Using library integration

Say the addon has a library integration feature. Use it to add some movie to your library and locate the generated strm file. Open it in text editor and you will see the final url to use for playing the movie you have added. If all parameters inside the url are supported by Meta, then you can use it by adding a simple CommandSequence. For example if the strm contains:

plugin://plugin.video.example/tt1234567/play

Then use the following CommandSequence:

[
 {
  "link": "plugin://plugin.video.example/{imdb}/play"
 }
]

####Using search

Say the addon we are adding also has a search feature that allows the user to enter free text and returns a folder listing all movie results.

A. locate the search function inside the addon's code. Normally searching for the word 'keyboard' will get you close.

B. identify what the code does with the entered search phrase. In some addons a plugin url would be generated and Container.Update would be executed with that url. If that's the case then just print the url and see the printed url in kodi.log. If all parameters in the url are supported then replace the parameters in the url as decsribed earlier (in 2) and use it as the link in the CommandSequence (followed by any required steps).

In other cases a funtion would be called after the user enters a search phrase passing the entered text as an argument. Lets assume that in our example there is such a function call to a function named do_search. Now we need a way to call do_search from Meta using a url. To do this find the part of code that parses args (usually this is written at the bottom of the main python file) and locate which args are needed in order to call do_search with the search phrase. Lets assume for our example we need to pass mode=2 to call do_search and the search phrase is pased using q=<search_phrase>. Then the CommandSequence to use (prefering 720P) is:

[
 {
  "link": "plugin://plugin.video.example/?mode=2&q={title}",
  "steps": ["{title}", "\[720p\].*"]
 },
 {
  "link": "plugin://plugin.video.example/?mode=2&q={title}",
  "steps": ["{title}", ".*"]
 }     
]

Only if it is absolutely not possible to send a search term to the addon via plugin:// URL, you may try to use a keyboard step. Here is an example:

[
 {
  "link": "plugin://plugin.video.example",
  "steps": ["Search", "keyboard: {title}", "{title}", "\[720p\].*"]
 },
 {
  "link": "plugin://plugin.video.example",
  "steps": ["Search", "keyboard: {title}", "{title}", ".*"]
 }     
]
Clone this wiki locally