diff --git a/doc/reference/clapper/clapper-enhancers.md b/doc/reference/clapper/clapper-enhancers.md new file mode 100644 index 00000000..5d7ca398 --- /dev/null +++ b/doc/reference/clapper/clapper-enhancers.md @@ -0,0 +1,153 @@ +Title: Clapper Enhancers +Slug: clapper-enhancers + +### Overview + +Clapper Enhancers are special plugins loaded through `libpeas` for Clapper library. +The idea is to enhance it (including applications that use Clapper) with new +capabilities that do stuff outside of `GStreamer` scope of things without increasing +number of dependencies of Clapper itself (especially for features that not everyone needs). + +To avoid confusion with term "plugins" that `GStreamer` uses, the name "enhancers" +was choosen instead. + +In addition to writing enhancers in pure `C`, they can be written in any programmable +language that is supported by `libpeas` and works with Clapper library bindings +(examples being `Python`, `GJS` and `Vala`). This makes it possible for individual users +to add their own custom functionalities that they want to use individually. + +### Types + +Clapper gives three interfaces for writing enhancers for different things, these are: + +- [Extractable](extractable-enhancers.html) +- [Playlistable](playlistable-enhancers.html) +- [Reactable](reactable-enhancers.html) + +### Basics + +Each enhancer is a `libpeas` compatible module. As such it follows its requirements for +writing plugins and is a [class@GObject.Object] sublass implementing one or more of interfaces +that Clapper library provides. + +Due to the plugins nature, written enhancer can be either submitted to the main [Clapper Enhancers +repository](https://github.com/Rafostar/clapper-enhancers) when it seems useful for more than a single +application. Alternatively, it can be shipped as part your application. Users can also write their +own/custom local enhancer plugins. + +### Loading Enhancers + +Clapper will try to lazy load enhancer modules, meaning they will not be loaded unless they are used. +As an additional safety precaution, enhancers can be disallowed from their instances being created with +[property@Clapper.EnhancerProxy:target-creation-allowed]. Enhancers that operate on-demand +(when supported URI is given) such as [iface@Clapper.Extractable] and [iface@Clapper.Playlistable] +are allowed (enabled) by default, while [iface@Clapper.Reactable] are not. + +Environment variables: + +* `CLAPPER_ENHANCERS_PATH` - override for default path where Clapper loads enhancers from +* `CLAPPER_ENHANCERS_EXTRA_PATH` - additional path to scan for enhancer plugins + +While both allow to specify multiple directories (with `:` separation), applications and +users should mostly use extra path in order to add their own enhancers from non-standard +installation directory. They can override default path in case where they want to forbid +using stock enhancers for some reason. + +### Enhancer Proxies + +In order to create enhancers when needed and use them only within thread they were created in, +Clapper manages enhancer instances on its own. It gives applications proxy objects for +browsing and configuring them. + +Only after Clapper library is initialized, you can get either the global (application scope) list +([class@Clapper.EnhancerProxyList]) of enhancers proxies with [func@Clapper.get_global_enhancer_proxies] +or player scope with [method@Clapper.Player.get_enhancer_proxies]. + +Properties set on the global list will carry over to all created player instances afterwards. +While these set on a list from a player are applied to enhancers created by this player only. +You can use that to your advantage to only allow creation of some type of enhancer in only some +player instances. + +### Properties + +Some enhancers might want to expose some configuration. For this cases they should install +[class@GObject.Object] properties in their class. They must only use fundamental types from the list below: + +* boolean +* int +* uint +* double +* string + +They should include one or more of [flags@Clapper.EnhancerParamFlags]. +Properties in object can have `global`, `local`, neither or both flags at once. + +The ones with [Clapper.EnhancerParamFlags.GLOBAL] are for user to configure. They should +be exposed (ideally in the UI) and used for things that make sense to be set for all +applications at once (e.g. supported media codec by user device, preferred language, etc.). + +On the other hand, properties with [Clapper.EnhancerParamFlags.LOCAL] are for application scope +usage only. They never carry over to other apps, nor they can be set on global enhancers list. +Instead they are configured per player instance. + +When property is neither `global` or `local` it is considered to be plugin internal property. +Clapper will never access them, as such they can be of any type (not limited to above list). +This also makes properties that are already installed in base classes of subclassed object +not appear in the UI. + +When both flags are set, property will initially use globally set value by user while still +allowing application to override this value locally per player instance. + +Extra flags like [Clapper.EnhancerParamFlags.FILEPATH] and [Clapper.EnhancerParamFlags.DIRPATH] +can be used (usually with `string` type of property) in order to let application know that this +field holds a file/directory path and allow it to present file selection dialog to the user instead +of text entry. + +### Configuring Enhancers + +Applications browse properties of enhancer via [method@Clapper.EnhancerProxy.get_target_properties] +which returns a list of [class@GObject.ParamSpec]. By inspecting their `flags` application can know +whether property is `global`, `local` or both. + +Use [method@Clapper.EnhancerProxy.get_settings] to get a [class@Gio.Settings] with `global` properties +to read and write (note that only users should be able to change them, thus you might want to bind these +into some UI widgets for that). These can be (with user consent) set on either proxy from global proxies +list or the player one. + +Use [method@Clapper.EnhancerProxy.set_locally] to set `local` properties. These are meant for applications +to freely customize as they please. Remember that you can only set them on a enhancer proxy object belonging +to some player instance and not the global one. + +### Plugin Info File + +An enhancer plugin should be placed within directory that includes its [Peas] plugin +description file. It should be a text file with a `.plugin` extension and contain at least +following content: + +``` +[Plugin] +Module=example_enhancer +Name=Example Enhancer +Description=This enhancer serves as an example +Version=0.0.1 +``` + +* `Module` - module entry file name. It also acts as enhancer ID and should be unique for each. +It is recommended to use app/custom prefix in its name. +* `Name` - module friendly name for displaying in UI and such. +* `Description` - description to present to the user for what it does. +* `Version` - enhancer version. In order to lazy load enhancers, Clapper will cache each +enhancer data and olny reload it if version changes, so keep this always updated. + +If module is written in interpretable programming language it must also contain `Loader` key +with interpreter name (e.g. `Loader=python`). + +Some enhancer interfaces require additional fields to be put in this file. They are described +in the requirements of each one in their documentation pages that are listed in the +[Types section](clapper-enhancers.html#types). + +### Adding Enhancers to Flatpak App + +If you are using Clapper as part of a `Flatpak` application, you can get all the enhancers from their main repo as an extension +(info [here](https://github.com/flathub/com.github.rafostar.Clapper?tab=readme-ov-file#comgithubrafostarclapperenhancers)), +thus you do not need to build them yourself. diff --git a/doc/reference/clapper/clapper.toml.in b/doc/reference/clapper/clapper.toml.in index 27972bfb..d18b8e1f 100644 --- a/doc/reference/clapper/clapper.toml.in +++ b/doc/reference/clapper/clapper.toml.in @@ -66,6 +66,11 @@ base_url = "https://github.com/Rafostar/clapper/tree/master/" [extra] # The same order will be used when generating the index content_files = [ + "clapper-enhancers.md", + "extractable-enhancers.md", + "playlistable-enhancers.md", + "reactable-enhancers.md", + "migrating-to-010.md", ] content_images = [ "images/clapper-logo.svg", diff --git a/doc/reference/clapper/extractable-enhancers.md b/doc/reference/clapper/extractable-enhancers.md new file mode 100644 index 00000000..27bc692f --- /dev/null +++ b/doc/reference/clapper/extractable-enhancers.md @@ -0,0 +1,76 @@ +Title: Extractable Enhancers +Slug: extractable-enhancers + +### Overview + +[iface@Clapper.Extractable] is an interface to implement enhancers that need to +resolve given URI into data that `GStreamer` will be able to play. While not +limited to, main use-case is for media information extraction. + +While implementer is free to write whole extraction by hand, he can alternatively +integrate some 3rd party library that does most of this work. In such case, extractable +enhancer is more of a wrapper for integrating said library. This is especially useful +if library that you want to use is written in different programming language than Clapper is. + +For the basics about writing enhancers see [Clapper Enhancers](clapper-enhancers.html). + +### Requirements + +Additional fields for `.plugin` info file: `X-Schemes` and `X-Hosts`. The former one should +hold the `;` separated list of supported URI schemes, while the latter is for hostnames. + +Example: + +``` +X-Schemes=https;expl +X-Hosts=example.com;other.example.com +``` + +With this in place, enhancer will be loaded and used for URIs that match combinations +of one of the schemes and hosts. The special rule is that when using some custom URI +scheme other than `http(s)`, `X-Hosts` can be skipped since such URI explicitly +says to use this module. + +Considering all of the above, this enhancer would try to extract URIs like: + +* `https://example.com/video_id=ABCD` +* `expl://video.it?id=ABCD` + +It would not act however for: + +* `https://video.it?id=ABCD` +* `qwerty://other.example.com/video_id=ABCD` + +An enhancer of this type must implement [vfunc@Clapper.Extractable.extract] virtual method. + +### Harvesting data + +When [vfunc@Clapper.Extractable.extract] is called, newly made [class@Clapper.Harvest] +is passed as this function argument. Implementation is responsible for filling it with +data (see [method@Clapper.Harvest.fill]) that can be played. Such content can be either +a resolved URI to actual media file or some streaming manifest (like `HLS` or `DASH`). + +During extract function, implementation might optionally add media tags such as title +(which will be merged with tags of [class@Clapper.MediaItem]) and extra HTTP request +headers if any are required to access this content. + +### Multiple items extraction + +It is possible to handle URIs which would normally return more than one media item to play. +Examples being playlists, search queries, related videos, etc. + +This can be handled in two ways, depending on set media type: + +1. `text/uri-list` +2. `application/clapper-playlist` + +If you use the first option, harvest should be filled with idividual URIs one per line. +Clapper will use its built-in URI list parser to create a media item for each URI and +place them in its playback queue. This is equivalent of creating [class@Clapper.MediaItem] +for each of these URIs without setting any tags in it initially. + +The second option requires for this enhancer to also implement [iface@Clapper.Playlistable] +interface. In this case, you can fill harvest with ANY kind of data considering that +[vfunc@Clapper.Playlistable.parse] of your own enhancer will be used with the data you +passed. With this, you can add more info to media items such as extra tags, timeline markers +or subtitle URI. Useful if your extractor extracts both URIs and tags in one go. diff --git a/doc/reference/clapper/meson.build b/doc/reference/clapper/meson.build index fdf3df71..023b30bd 100644 --- a/doc/reference/clapper/meson.build +++ b/doc/reference/clapper/meson.build @@ -6,6 +6,14 @@ clapper_toml = configure_file( install_dir: join_paths(datadir, 'doc', 'clapper'), ) +extra_md_files = [ + 'clapper-enhancers.md', + 'extractable-enhancers.md', + 'playlistable-enhancers.md', + 'reactable-enhancers.md', + 'migrating-to-010.md', +] + custom_target('clapper-doc', input: [ clapper_toml, @@ -23,6 +31,7 @@ custom_target('clapper-doc', '--content-dir=@0@'.format(meson.current_source_dir()), '@INPUT1@', ], + depend_files: extra_md_files, build_by_default: true, install: true, install_dir: join_paths(datadir, 'doc'), diff --git a/doc/reference/clapper/migrating-to-010.md b/doc/reference/clapper/migrating-to-010.md new file mode 100644 index 00000000..486213e2 --- /dev/null +++ b/doc/reference/clapper/migrating-to-010.md @@ -0,0 +1,44 @@ +Title: Migrating to Clapper 0.10 +Slug: migrating-to-010 + +### Replace Features with Enhancers + +Clapper 0.10 deprecates [class@Clapper.Feature] objects in favour [Clapper Enhancers](clapper-enhancers.html) +used via [class@Clapper.EnhancerProxy]. + +Old [class@Clapper.Feature] objects (including `mpris`, `discoverer` and `server`) are left for compatibility +reasons, but all apps using them are advised to migrate to enhancer plugins which already surpassed former +ones in what can be achieved with them. + +Since these are now in the form of plugins scanned during init, one of the differences is that you now check +their availablity at runtime instead of compile time like before. + +Something like this: + +```c +#if CLAPPER_HAVE_MPRIS + ClapperFeature *feature = CLAPPER_FEATURE (clapper_mpris_new ( + mpris_name, APP_NAME, APP_ID)); + clapper_player_add_feature (player, feature); + gst_object_unref (feature); +#endif +``` + +Can be implemented like this: + +```c +ClapperEnhancerProxyList *proxies = clapper_player_get_enhancer_proxies (player); +ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_get_proxy_by_module (proxies, "clapper-mpris"); + +if (proxy) { + clapper_enhancer_proxy_set_locally (proxy, + "own-name", mpris_name, + "identity", APP_NAME, + "desktop-entry", APP_ID, NULL); + clapper_enhancer_proxy_set_target_creation_allowed (proxy, TRUE); + gst_object_unref (proxy); +} +``` + +For more information how to use enhancers and how to write your own, +see [Clapper Enhancers](clapper-enhancers.html) documentation. diff --git a/doc/reference/clapper/playlistable-enhancers.md b/doc/reference/clapper/playlistable-enhancers.md new file mode 100644 index 00000000..8308369c --- /dev/null +++ b/doc/reference/clapper/playlistable-enhancers.md @@ -0,0 +1,39 @@ +Title: Playlistable Enhancers +Slug: playlistable-enhancers + +### Overview + +[iface@Clapper.Playlistable] is an interface to implement playlist parsers. +Allows to expand Clapper library with an ability to read data from which one +or more media items should be created. + +To load playlist within Clapper, just create a new media item which has an URI +leading to data that playlistable enhancer will act upon. After parsing, that item +will be merged with first parsed item and the rest will be inserted into queue after +its position. + +Essentially, such enhancer inserts items from a playlist into playback queue upon +which Clapper operates. It can also handle nested playlits (a playlist URI within +another playlist) with unlimited amount of nested levels. + +For the basics about writing enhancers see [Clapper Enhancers](clapper-enhancers.html). + +### Requirements + +Additional fields for `.plugin` info file: + +* `X-Data-Prefix` - describe text that data should start with +* `X-Data-Contains` - data must contain given phrase +* `X-Data-Regex` - regular expression to run on data + +These are used by `typefinder` to determine whether given data is a playlist for +this enhancer to handle. At least one of the above must be added to plugin info file. + +An enhancer of this type must implement [vfunc@Clapper.Playlistable.parse] virtual method. + +### Parsing data + +When [vfunc@Clapper.Playlistable.parse] is called, an empty [class@Gio.ListStore] is +passed as this function argument. Implementation is responsible for parsing data, creating +[class@Clapper.MediaItem] objects and adding them to that list store. While doing so, it +can also populate each media item tags, timeline markers and/or set subtitle URI. diff --git a/doc/reference/clapper/reactable-enhancers.md b/doc/reference/clapper/reactable-enhancers.md new file mode 100644 index 00000000..c530aa0b --- /dev/null +++ b/doc/reference/clapper/reactable-enhancers.md @@ -0,0 +1,23 @@ +Title: Reactable Enhancers +Slug: reactable-enhancers + +### Overview + +[iface@Clapper.Reactable] is an interface to implement enhancers that react to the +playback and/or events that should influence it. + +Such enhancer can work not only in a way that triggers external actions due to some +playback events, but also in reverse - alters playback or its queue due to some +external event. It can do so by getting a hold of the player that given enhancer +instance reacts to with [method@Clapper.Reactable.get_player]. + +For the basics about writing enhancers see [Clapper Enhancers](clapper-enhancers.html). + +### Requirements + +An enhancer of this type should implement any of the [iface@Clapper.Reactable] virtual +methods that it needs. + +Note that when implementing [vfunc@Clapper.Reactable.queue_item_removed] you probably +also want to implement [vfunc@Clapper.Reactable.queue_cleared] as the former is not +called for each item when clearing the whole queue for performance reasons.