0
# Plugin System
1
2
Streamlink's plugin system enables support for hundreds of streaming services through a unified, extensible architecture. Plugins use decorators to define URL patterns and command-line arguments, making it easy to add support for new streaming services.
3
4
## Capabilities
5
6
### Plugin Base Class
7
8
The foundation class that all plugins inherit from, providing common functionality for URL matching, option handling, and stream extraction.
9
10
```python { .api }
11
class Plugin:
12
def __init__(self, session, url, options=None):
13
"""
14
Initialize plugin instance.
15
16
Parameters:
17
- session: Streamlink session instance
18
- url: URL that matched this plugin
19
- options: Optional Options instance for plugin-specific settings
20
"""
21
22
def set_option(self, key: str, value) -> None:
23
"""
24
Set plugin-specific option.
25
26
Parameters:
27
- key: Option name
28
- value: Option value
29
"""
30
31
def get_option(self, key: str):
32
"""
33
Get plugin-specific option value.
34
35
Parameters:
36
- key: Option name
37
38
Returns:
39
Option value or None if not set
40
"""
41
42
def streams(self, stream_types=None, sorting_excludes=None) -> dict[str, Stream]:
43
"""
44
Extract streams from the plugin's URL.
45
46
Parameters:
47
- stream_types: List of stream types to include (default: all)
48
- sorting_excludes: List of stream qualities to exclude from sorting
49
50
Returns:
51
Dictionary mapping quality names to Stream instances
52
53
Raises:
54
NoStreamsError: If no streams are found
55
PluginError: If extraction fails
56
"""
57
58
def stream_weight(self, stream) -> tuple:
59
"""
60
Calculate stream quality weight for sorting.
61
62
Parameters:
63
- stream: Stream instance to weigh
64
65
Returns:
66
Tuple representing stream quality weight for sorting
67
"""
68
```
69
70
Plugin instances have several important attributes available:
71
72
```python { .api }
73
# Plugin attributes available in all plugin instances
74
session: Streamlink # Streamlink session instance
75
options: Options # Plugin options
76
cache: Cache # Plugin cache object
77
matchers: list # URL pattern matchers
78
arguments: Arguments # Plugin argument definitions
79
matches: list # Current URL match results
80
matcher: Pattern # Current matching pattern
81
match: Match # Current match result
82
83
# Metadata attributes (can be set by plugins)
84
id: str # Unique plugin identifier
85
title: str # Stream title
86
author: str # Stream author/channel
87
category: str # Stream category
88
```
89
90
### Plugin Decorators
91
92
Decorators for defining plugin URL patterns and command-line arguments.
93
94
```python { .api }
95
def pluginmatcher(pattern, priority=NORMAL_PRIORITY, name=None):
96
"""
97
Decorator to define URL pattern matchers for plugins.
98
99
Parameters:
100
- pattern: Regular expression pattern to match URLs
101
- priority: Matcher priority (higher = checked first)
102
- name: Optional name for the matcher
103
104
Usage:
105
@pluginmatcher(r'https?://example\.com/(\w+)')
106
class ExamplePlugin(Plugin):
107
...
108
"""
109
110
def pluginargument(name, **kwargs):
111
"""
112
Decorator to define command-line arguments for plugins.
113
114
Parameters:
115
- name: Argument name (converted to CLI format)
116
- **kwargs: argparse.ArgumentParser.add_argument() parameters
117
118
Usage:
119
@pluginargument('username', help='Account username')
120
@pluginargument('password', help='Account password', sensitive=True)
121
class ExamplePlugin(Plugin):
122
...
123
"""
124
```
125
126
### Priority Constants
127
128
Priority levels for URL pattern matching, controlling the order plugins are checked.
129
130
```python { .api }
131
HIGH_PRIORITY = 30 # Highest priority - checked first
132
NORMAL_PRIORITY = 20 # Default priority for most plugins
133
LOW_PRIORITY = 10 # Lower priority
134
NO_PRIORITY = 0 # Lowest priority - checked last
135
```
136
137
### Plugin Options Classes
138
139
Classes for managing plugin arguments and options.
140
141
```python { .api }
142
class PluginOptions(Options):
143
"""Alias for Options class used in plugin contexts"""
144
145
class PluginArguments:
146
"""Collection of plugin command-line arguments"""
147
148
class PluginArgument:
149
"""Individual plugin argument definition with CLI integration"""
150
```
151
152
## Usage Examples
153
154
### Basic Plugin Structure
155
156
```python
157
import re
158
from streamlink.plugin import Plugin, pluginmatcher, pluginargument
159
from streamlink.stream import HTTPStream
160
161
@pluginmatcher(r'https?://example\.com/watch/(\w+)')
162
@pluginargument('quality', choices=['720p', '1080p'], default='best',
163
help='Stream quality to extract')
164
class ExamplePlugin(Plugin):
165
def _get_streams(self):
166
# Extract stream URL from webpage
167
stream_url = self._extract_stream_url()
168
169
if stream_url:
170
return {
171
'best': HTTPStream(self.session, stream_url)
172
}
173
174
return {}
175
176
def _extract_stream_url(self):
177
# Implementation to extract stream URL
178
match = self.match
179
video_id = match.group(1)
180
181
# Fetch and parse webpage
182
res = self.session.http.get(self.url)
183
# ... parsing logic ...
184
185
return extracted_url
186
```
187
188
### Multiple URL Patterns
189
190
```python
191
@pluginmatcher(r'https?://example\.com/watch/(\w+)', priority=HIGH_PRIORITY)
192
@pluginmatcher(r'https?://example\.com/live/(\w+)')
193
@pluginmatcher(r'https?://(?:www\.)?example\.com/v/(\w+)', name='legacy')
194
class ExamplePlugin(Plugin):
195
def _get_streams(self):
196
# Check which matcher was used
197
if self.matcher and self.matcher.name == 'legacy':
198
return self._handle_legacy_url()
199
else:
200
return self._handle_modern_url()
201
```
202
203
### Plugin Arguments and Options
204
205
```python
206
@pluginmatcher(r'https?://premium\.example\.com/(\w+)')
207
@pluginargument('username', required=True,
208
help='Premium account username')
209
@pluginargument('password', required=True, sensitive=True,
210
help='Premium account password')
211
@pluginargument('quality', choices=['480p', '720p', '1080p'],
212
default='best', help='Stream quality preference')
213
class PremiumExamplePlugin(Plugin):
214
def _get_streams(self):
215
# Access plugin arguments
216
username = self.get_option('username')
217
password = self.get_option('password')
218
quality_pref = self.get_option('quality')
219
220
# Authenticate using credentials
221
if not self._authenticate(username, password):
222
raise PluginError('Authentication failed')
223
224
# Extract streams based on quality preference
225
streams = self._extract_streams()
226
227
if quality_pref != 'best':
228
# Filter streams by preference
229
return {k: v for k, v in streams.items()
230
if k == quality_pref or k in ['best', 'worst']}
231
232
return streams
233
```
234
235
### Advanced Stream Extraction
236
237
```python
238
from streamlink.stream import HLSStream, DASHStream
239
240
@pluginmatcher(r'https?://adaptive\.example\.com/(\w+)')
241
class AdaptiveExamplePlugin(Plugin):
242
def _get_streams(self):
243
streams = {}
244
245
# Get stream metadata
246
metadata = self._get_stream_metadata()
247
248
# Add HLS streams if available
249
if metadata.get('hls_url'):
250
hls_streams = HLSStream.parse_variant_playlist(
251
self.session, metadata['hls_url']
252
)
253
streams.update(hls_streams)
254
255
# Add DASH streams if available
256
if metadata.get('dash_url'):
257
dash_streams = DASHStream.parse_manifest(
258
self.session, metadata['dash_url']
259
)
260
streams.update(dash_streams)
261
262
return streams
263
264
def _get_stream_metadata(self):
265
# Extract stream URLs from API or webpage
266
api_url = f"https://api.example.com/stream/{self.match.group(1)}"
267
res = self.session.http.get(api_url)
268
return res.json()
269
```
270
271
### Plugin with Caching
272
273
```python
274
@pluginmatcher(r'https?://cached\.example\.com/(\w+)')
275
class CachedExamplePlugin(Plugin):
276
def _get_streams(self):
277
video_id = self.match.group(1)
278
cache_key = f"stream_data_{video_id}"
279
280
# Try to get cached data
281
cached_data = self.cache.get(cache_key)
282
283
if cached_data is None:
284
# Fetch fresh data
285
cached_data = self._fetch_stream_data(video_id)
286
287
# Cache for 5 minutes
288
self.cache.set(cache_key, cached_data, expires=300)
289
290
# Create streams from cached data
291
return self._create_streams(cached_data)
292
```
293
294
### Error Handling in Plugins
295
296
```python
297
from streamlink.exceptions import PluginError, NoStreamsError
298
299
@pluginmatcher(r'https?://robust\.example\.com/(\w+)')
300
class RobustExamplePlugin(Plugin):
301
def _get_streams(self):
302
try:
303
# Attempt to extract streams
304
streams = self._extract_streams()
305
306
if not streams:
307
raise NoStreamsError("No streams found for this URL")
308
309
return streams
310
311
except requests.RequestException as err:
312
raise PluginError(f"Failed to fetch stream data: {err}")
313
except ValueError as err:
314
raise PluginError(f"Invalid stream data format: {err}")
315
```