or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-validation.mdindex.mdoptions-configuration.mdplugin-system.mdsession-management.mdstream-access.mdutilities.md

plugin-system.mddocs/

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

```