Skip to content

Commit

Permalink
Documentation refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
JosefNemec committed Oct 31, 2020
1 parent a9e5dc1 commit 6faa96b
Show file tree
Hide file tree
Showing 22 changed files with 251 additions and 141 deletions.
20 changes: 10 additions & 10 deletions doc/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@
#### 5.3.0

* **Breaking Changes**:
* Playnite will no longer load plugins that reference non-SDK Playnite assemblies. See [this page](tutorials/plugins/plugins.md#referencing-playnite-assemblies) for more information.
* Playnite will no longer load plugins that reference non-SDK Playnite assemblies. See [this page](tutorials/extensions/plugins.md#referencing-playnite-assemblies) for more information.
* Playnite will no longer install extensions and themes that don't have proper version specified. The version string must a valid [.NET version string](https://docs.microsoft.com/en-us/dotnet/api/system.version)!

* **Now obsolete**:

* These changes do not break compatibility in current version (mentioned methods are still available in SDK), but they will be made breaking in future major Playnite updates.
* Added `Id` to extension and theme [manifests](tutorials/extensionsManifest.md). This field is currently not mandatory for existing extensions (Playnite 8 will load installed extensions without an ID, but will not install new ones without an ID), but should be provided for better extension installation and update support. Toolbox will not pack new extensions unless `Id` is present.
* The way custom menu items are implemented (for main menu and game menu) has been completely changed (the old system still works temporarily). See [related documentation page](tutorials/menus.md) for more information.
* Added `Id` to extension and theme [manifests](tutorials/extensions/extensionsManifest.md). This field is currently not mandatory for existing extensions (Playnite 8 will load installed extensions without an ID, but will not install new ones without an ID), but should be provided for better extension installation and update support. Toolbox will not pack new extensions unless `Id` is present.
* The way custom menu items are implemented (for main menu and game menu) has been completely changed (the old system still works temporarily). See [related documentation page](tutorials/extensions/menus.md) for more information.
* [NavigationChanged](xref:Playnite.SDK.IWebView) from IWebView is now obsolete, use new `LoadingChanged` instead.

* New
* Metadata plugins can now provide `Features`, `AgeRating`, `Series`, `Region` and `Platform` data.
* Extensions can now provide [custom menu items](tutorials/menus.md) for game menus, including nested entries.
* Extensions can now provide [custom menu items](tutorials/extensions/menus.md) for game menus, including nested entries.
* Most useful Playnite settings are now exposed in [IPlayniteSettingsAPI](xref:Playnite.SDK.IPlayniteSettingsAPI).
* [ActivateGlobalProgress](xref:Playnite.SDK.IDialogsFactory) method to show blocking progress dialog.
* [LoadingChanged](xref:Playnite.SDK.IWebView) event for WebViews.
Expand All @@ -44,11 +44,11 @@
* [Toolbox](tutorials/toolbox.md) utility has been reworked and accepts different arguments then previously.

* New
* Library plugins can now support extra [capabilities](tutorials/plugins/libraryPlugins.md#capabilities).
* Library plugins can now support extra [capabilities](tutorials/extensions/libraryPlugins.md#capabilities).
* Added [ImportGame](xref:Playnite.SDK.IGameDatabase.ImportGame(Playnite.SDK.Models.GameInfo)) methods to more easily add new games to the library.
* Added [OpenPluginSettings](xref:Playnite.SDK.IMainViewAPI.OpenPluginSettings(System.Guid)) method to open view with extension settings (also accessible via `OpenSettingsView` method inherited from `Plugin` class).
* Added [StartGame](xref:Playnite.SDK.IPlayniteAPI.StartGame(System.Guid)).
* Added [UriHandler](xref:Playnite.SDK.IPlayniteAPI.UriHandler) for registering of custom [URI method actions](tutorials/plugins/uriSupport.md).
* Added [UriHandler](xref:Playnite.SDK.IPlayniteAPI.UriHandler) for registering of custom [URI method actions](tutorials/extensions/uriSupport.md).
* Added option settings when creating offscreen web view (currently only option to disable JavaScript execution).
* Added `OnGameSelected`, `OnApplicationStopped` and `OnLibraryUpdated` events.
* Added `Features` game field and appropriate support for it in metadata plugins.
Expand All @@ -58,7 +58,7 @@
#### 5.1.0

* New
* Added support for creating metadata providers via [plugins](tutorials/plugins/metadataPlugins.md).
* Added support for creating metadata providers via [plugins](tutorials/extensions/metadataPlugins.md).
* [ChooseImageFile](xref:Playnite.SDK.IDialogsFactory) method for dialogs API. **Only available in Desktop mode.**
* [ChooseItemWithSearch](xref:Playnite.SDK.IDialogsFactory) method for dialogs API. **Only available in Desktop mode.**

Expand Down Expand Up @@ -87,14 +87,14 @@

* **Breaking Changes**:
* In order to unify terminology used in Playnite's UI and that in SDK, some classes and class members were renamed.
* Extensions (both plugins and scripts) have to provide [extension manifest](tutorials/extensionsManifest.md) otherwise they won't be loaded.
* Extensions (both plugins and scripts) have to provide [extension manifest](tutorials/extensions/extensionsManifest.md) otherwise they won't be loaded.
* Various information about extension (author, version etc.) must be now stored in manifest file.
* Both plugins and scripts have to be stored in the same folder called `Extensions` (rather then in separate `Plugins` or `Scripts` folders).
* Signature for default C# plugins has changed and they now have to implement `IGenericPlugin` interface to be loaded.

* New Plugin types. There are now two types of plugins that can be implemented:
* Generic Plugin: Same as the old plugins.
* [Library Plugin](tutorials/plugins/libraryPlugins.md): Used to add new library providers responsible for automatic game import from various sources.
* [Library Plugin](tutorials/extensions/libraryPlugins.md): Used to add new library providers responsible for automatic game import from various sources.
* All existing supported library importers (Steam, GOG etc.) are now distributed as [library plugins](https://github.com/JosefNemec/Playnite/tree/master/source/Plugins).

* New APIs:
Expand All @@ -115,5 +115,5 @@
#### 1.1.0

* **Breaking Change**: Scripts and Plugins must be place in subfolders rather then directly inside of `Scripts` or `Plugins` folders.
* New: `OnGameStarting` event that will execute before game is started. See [events](tutorials/scripts/scriptingEvents.md) for use from scripts.
* New: `OnGameStarting` event that will execute before game is started. See [events](tutorials/extensions/events.md) for use from scripts.
* New: [ShowErrorMessage](xref:Playnite.SDK.IDialogsFactory.ShowErrorMessage(System.String,System.String)) method in `IDialogsFactory`
16 changes: 16 additions & 0 deletions doc/tutorials/extensions/dataDirectory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Script data directory
=====================

Extensions should store any generated data in a designated extension data directory instead of its installation directory, because installation directory gets purged during extension installation or update.

Scripts
---------------------

To get script data directory, use `CurrentExtensionDataPath` global variable.

To get installation directory of currently running script, use `CurrentExtensionInstallPath` global variable.

Plugins
---------------------

To get the directory, call [GetPluginUserDataPath](xref:Playnite.SDK.Plugins.Plugin.GetPluginUserDataPath) method. The method returns full path designated to to a specific plugin. The same directory is used to store plugin [settings](pluginSettings.md).
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ Reacting to events
Basics
---------------------

Playnite's API allows script to react to various events like when game is started or installed.
Playnite's API allows extensions to react to various events like when game is started or installed.

Available Events
---------------------

|PowerShell Name | Python Name | Event | Passed Arguments |
|PowerShell Name / Plugin name | Python Name | Event | Passed Arguments |
| - | - | - | - |
| OnGameStarting | on_game_starting | Before game is started. | [Game](xref:Playnite.SDK.Models.Game) |
| OnGameStarted | on_game_started | Game started running. | [Game](xref:Playnite.SDK.Models.Game) |
Expand All @@ -21,6 +21,16 @@ Available Events
| OnApplicationStopped | on_application_stopped | Playnite is shutting down. | None |
| OnLibraryUpdated | on_library_updated | Library was updated. | None |


Scripts
---------------------



Plugins
---------------------


Example - Handling start/stop events
---------------------

Expand All @@ -30,6 +40,14 @@ To have a code executed on selected event define function with specific name in

Following example writes name of currently playing game into a text file.

# [C#](#tab/csharp)
```csharp
public override void OnGameStarted(Game game)
{
logger.Info($"Game started: {game.Name}");
}
```

# [PowerShell](#tab/tabpowershell)
```powershell
function global:OnGameStarted()
Expand All @@ -54,40 +72,16 @@ def on_game_started(game):

This example writes name of game that stopped running and the time game was running for into a text file.

# [PowerShell](#tab/tabpowershell)
```powershell
function global:OnGameStopped()
# [C#](#tab/csharp)
```csharp
public override void OnGameStopped(Game game, double elapsedSeconds)
{
param(
$game,
$elapsedSeconds
)
"$($game.Name) was running for $elapsedSeconds seconds" | Out-File "StoppedGame.txt"
logger.Info($"{game.Name} was running for {elapsedSeconds} seconds");
}
```

# [IronPython](#tab/tabpython)
```python
def on_game_stopped(game, elapsed_seconds):
with open("StoppedGame.txt", "w") as text_file:
text_file.write("{0} was running for {1} seconds".format(game.Name, elapsed_seconds))
```
***

### Full File Examples

# [PowerShell](#tab/tabpowershell)
```powershell
function global:OnGameStarted()
{
param(
$game
)
$game.Name | Out-File "RunningGame.txt"
}
function global:OnGameStopped()
{
param(
Expand All @@ -101,12 +95,7 @@ function global:OnGameStopped()

# [IronPython](#tab/tabpython)
```python
def on_game_started(game):
with open("RunningGame.txt", "w") as text_file:
text_file.write(game.Name)

def on_game_stopped(game, elapsed_seconds):
with open("StoppedGame.txt", "w") as text_file:
text_file.write("{0} was running for {1} seconds".format(game.Name, elapsed_seconds))
```
***
File renamed without changes.
File renamed without changes.
File renamed without changes.
71 changes: 71 additions & 0 deletions doc/tutorials/extensions/intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Introduction to Playnite extensions

Basics
---------------------

Playnite can be extended via extensions implemented via scripts and plugins:

- Scripts: [PowerShell](https://docs.microsoft.com/en-us/powershell/) and [IronPython](http://ironpython.net/) scripts are supported.
- Plugins: Any .NET Framework compatible language can be used (`C#`, `VB.NET`, `F#` and others).

Extensions fall under several categories of extended functionality that are available based on selected implementation:

| Extension | Scripts | Plugins |
| -- | :--: | :--: |
| Executable menu entry |||
| Reacting to game events |||
| Library importer | ||
| Metadata provider | ||

- `Executable menu entry` - adds new executable menu entry under main menu's `Scripts` sub sections.
- `Reacting to game events` - executes code when various game events occurs, like when game is started or stopped for example.
- `Library importer` - provides automatic import of games from various sources. For example all currently supported external clients (Steam, GOG, Origin etc.) [are implemented](https://github.com/JosefNemec/Playnite/tree/master/source/Plugins) via this extension type.
- `Metadata provider` - provides metadata for games in Playnite. Our default metadata provider, IGDB.com, is also [implemented as a metadata plugin](https://github.com/JosefNemec/Playnite/tree/master/source/Plugins/IGDBMetadata).

Creating Extensions
---------------------

It's highly recommended to use [Toolbox](../toolbox.md) utility to create new extensions. It will generate base directory structure and all files needed for you.

### 1. Directory structure and location

First create new extension folder inside of Playnite's `Extensions` directory. Location of `Extensions` directory differs based on Playnite's installation type:

- Portable version: `Extensions` folder directly inside of Playnite's installation location.
- Installed version: `%AppData%\Playnite\Extensions` folder.

> [!WARNING]
> Automatic installations and updates via `.pext` and `.pthm` files always replace the extension/theme directory completely. Meaning that any files that are not part of the installation package will be lost during installation process! It is highly recommended to store generated files in a separate extensions data folder. See [Data directories](dataDirectory.md) page to learn more about extension directories.
### 2. Manifest file

Every extension must provide valid [manifest file](extensionsManifest.md) in order to be recognized and loaded by Playnite. Manifest is YAML formatted file called `extension.yaml` that must be stored inside of extension directory.

Resulting folder structure should look something like this:
```
├──Install directory or %AppData%\Playnite
│ └── Extensions
│ └── PluginFolder
│ ├── extension.yaml
│ └── scriptFileName.py or pluginFileName.dll
```

See manifest file [documentation page](extensionsManifest.md) for more information about manifest contents.

### 3. Implementing extension

For scripts see [scripting introduction page](scripting.md).

For plugins see [plugins introduction page](plugins.md).

Loading extensions
---------------------

Extensions are loaded automatically by Playnite at every startup (unless extension is disabled via settings menu). Script can be reloaded at runtime via `Tools -> Reload Scripts` menu. Plugins can't be reloaded at runtime.

Distribution
---------------------

Use [Toolbox](../toolbox.md#packing-extensions) utility to package an extension or a theme and distribute `.pext` or `.pthm` file to users.

The best place to share extensions is official Playnite forum, specifically [extension database](https://playnite.link/forum/forum-3.html) sub-forum.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Working with Game Database
Working with game library
=====================

Introduction
Expand All @@ -12,19 +12,30 @@ Handling Games

To get list of all games in library use [Database](xref:Playnite.SDK.IPlayniteAPI.Database) property from `IPlayniteAPI` and [Games](xref:Playnite.SDK.IGameDatabase.Games) collection.

# [C#](#tab/csharp)
```csharp
foreach (var game in PlayniteApi.Database.Games)
{
// Do stuff with a game
}

// Get a game with known Id
var game = $PlayniteApi.Database.Games[SomeGuidId];
```

# [PowerShell](#tab/tabpowershell)
```powershell
# Get all games
$games = $PlayniteApi.Database.Games
# Get game with known Id
$game = $PlayniteApi.Database.Games[SomeGuidId]
# Get a game with known Id
$game = $PlayniteApi.Database.Games[$SomeGuidId]
```

# [IronPython](#tab/tabpython)
```python
# Get all games
games = PlayniteApi.Database.Games
# Get game with known Id
# Get a game with known Id
game = PlayniteApi.Database.Games[SomeGuidId]
```
***
Expand All @@ -33,6 +44,12 @@ game = PlayniteApi.Database.Games[SomeGuidId]

To add a new game create new instance of [Game](xref:Playnite.SDK.Models.Game) class and call `Add` method from [Games](xref:Playnite.SDK.IGameDatabase.Games) collection.

# [C#](#tab/csharp)
```csharp
var newGame = new Game("New Game");
PlayniteApi.Database.Games.Add(newGame);
```

# [PowerShell](#tab/tabpowershell)
```powershell
$newGame = New-Object "Playnite.SDK.Models.Game"
Expand All @@ -52,9 +69,16 @@ PlayniteApi.Database.Games.Add(new_game)

Changing properties on a `Game` object doesn't automatically update the game in Playnite's database and changes are lost with application restart. To make permanent changes game object must be updated in database manually using `Update` method from [Games](xref:Playnite.SDK.IGameDatabase.Games) collection.

# [C#](#tab/csharp)
```csharp
var game = PlayniteApi.Database.Games[SomeId];
game.Name = "Changed Name";
PlayniteApi.Database.Games.Update(game);
```

# [PowerShell](#tab/tabpowershell)
```powershell
$game = $PlayniteApi.Database.Games[SomeId]
$game = $PlayniteApi.Database.Games[$SomeId]
$game.Name = "Changed Name"
$PlayniteApi.Database.Games.Update($game)
```
Expand All @@ -71,16 +95,19 @@ PlayniteApi.Database.Games.Update(game)

To remove game from database use `Remove` method from [Games](xref:Playnite.SDK.IGameDatabase.Games) collection.

# [C#](#tab/csharp)
```csharp
PlayniteApi.Database.Games.Remove(SomeId);
```

# [PowerShell](#tab/tabpowershell)
```powershell
$game = $PlayniteApi.Database.Games[SomeId]
$PlayniteApi.Database.Games.Remove($game.Id)
$PlayniteApi.Database.Games.Remove($SomeId)
```

# [IronPython](#tab/tabpython)
```python
game = PlayniteApi.Database.Games[SomeId]
PlayniteApi.Database.Games.Remove(game.Id)
PlayniteApi.Database.Games.Remove(SomeId)
```
***

Expand Down Expand Up @@ -114,9 +141,15 @@ All game related image files are stored in game database itself, with only refer

Game cover images are referenced in [CoverImage](xref:Playnite.SDK.Models.Game.CoverImage) property. To save a file first get the file record by calling [GetFullFilePath](xref:Playnite.SDK.IGameDatabaseAPI.GetFullFilePath(System.String)) method. `GetFullFilePath` returns full path to a file on the disk drive.

# [C#](#tab/csharp)
```csharp
var game = PlayniteApi.Database.Games[SomeId];
var coverPath = PlayniteApi.Database.GetFullFilePath(game.CoverImage);
```

# [PowerShell](#tab/tabpowershell)
```powershell
$game = $PlayniteApi.Database.Games[SomeId]
$game = $PlayniteApi.Database.Games[$SomeId]
$coverPath = $PlayniteApi.Database.GetFullFilePath($game.CoverImage)
```

Expand All @@ -133,6 +166,14 @@ Changing cover image involves several steps. First remove original image by call

Following example changes cover image of first game in database:

# [C#](#tab/csharp)
```csharp
var game = PlayniteApi.Database.Games[SomeId];
PlayniteApi.Database.RemoveFile(game.CoverImage);
game.CoverImage = PlayniteApi.Database.AddFile(@"c:\file.png", game.Id);
PlayniteApi.Database.Games.Update(game);
```

# [PowerShell](#tab/tabpowershell)
```powershell
$game = $PlayniteApi.Database.Games[SomeId]
Expand Down
File renamed without changes.
Loading

0 comments on commit 6faa96b

Please sign in to comment.