reeln-plugin-meta 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.11", "3.12", "3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: astral-sh/setup-uv@v5
20
+ with:
21
+ enable-cache: true
22
+
23
+ - name: Set up Python ${{ matrix.python-version }}
24
+ run: uv python install ${{ matrix.python-version }}
25
+
26
+ - name: Create venv
27
+ run: uv venv --python ${{ matrix.python-version }}
28
+
29
+ - name: Install reeln-cli
30
+ run: uv pip install "git+https://github.com/StreamnDad/reeln-cli"
31
+
32
+ - name: Install dependencies
33
+ run: uv pip install -e ".[dev]"
34
+
35
+ - name: Lint
36
+ run: uv run ruff check .
37
+
38
+ - name: Type check
39
+ run: uv run mypy reeln_meta_plugin/
40
+
41
+ - name: Test
42
+ run: uv run python -m pytest tests/ -n auto --cov=reeln_meta_plugin --cov-branch --cov-fail-under=100 -q
@@ -0,0 +1,47 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ environment: release
12
+ permissions:
13
+ id-token: write
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: astral-sh/setup-uv@v5
19
+ with:
20
+ enable-cache: true
21
+
22
+ - name: Set up Python
23
+ run: uv python install 3.11
24
+
25
+ - name: Create venv
26
+ run: uv venv --python 3.11
27
+
28
+ - name: Install reeln-cli
29
+ run: uv pip install "git+https://github.com/StreamnDad/reeln-cli"
30
+
31
+ - name: Install dependencies
32
+ run: uv pip install -e ".[dev]"
33
+
34
+ - name: Lint
35
+ run: uv run ruff check .
36
+
37
+ - name: Type check
38
+ run: uv run mypy reeln_meta_plugin/
39
+
40
+ - name: Test
41
+ run: uv run python -m pytest tests/ -n auto --cov=reeln_meta_plugin --cov-branch --cov-fail-under=100 -q
42
+
43
+ - name: Build
44
+ run: uv build
45
+
46
+ - name: Publish to PyPI
47
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,50 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ *.egg
7
+ dist/
8
+ build/
9
+ .venv/
10
+ venv/
11
+ *.whl
12
+
13
+ # Testing / Coverage
14
+ .coverage
15
+ htmlcov/
16
+ .pytest_cache/
17
+ .tox/
18
+
19
+ # Media — prevent accidental video commits
20
+ *.mkv
21
+ *.mp4
22
+ *.mov
23
+ *.avi
24
+ *.webm
25
+ *.ts
26
+
27
+ # Project artifacts
28
+ secrets/
29
+ output/
30
+ .tmp/
31
+
32
+ # AI dev docs — dev-only, not tracked
33
+ CLAUDE.md
34
+ AGENTS.md
35
+ .claude/
36
+
37
+ # IDE
38
+ .idea/
39
+ .vscode/
40
+ *.swp
41
+ *.swo
42
+ *~
43
+
44
+ # OS
45
+ .DS_Store
46
+ Thumbs.db
47
+
48
+ # Environment
49
+ .env
50
+ .env.*
@@ -0,0 +1,45 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/).
6
+
7
+ ## [0.4.0] - 2026-03-09
8
+
9
+ ### Added
10
+
11
+ - `graph_api.py` module — shared HTTP helpers (`http_post`, `format_meta_error`, `GraphAPIError`)
12
+ - Cached authentication via `_ensure_auth()` — token read once per game session
13
+ - `ON_GAME_FINISH` hook handler — resets cached auth and game info between sessions
14
+ - `dry_run` config field (default `false`) — logs API calls without executing them
15
+
16
+ ### Changed
17
+
18
+ - `livestream.py` now delegates HTTP to `graph_api.py`; `LivestreamError` subclasses `GraphAPIError`
19
+ - Plugin registers both `ON_GAME_INIT` and `ON_GAME_FINISH` hooks
20
+
21
+ ## [0.3.0] - 2026-03-05
22
+
23
+ ### Added
24
+
25
+ - Feature flag system: each capability gated behind a boolean config field (default `false`)
26
+ - `create_livestream` feature flag for Facebook Live Video creation
27
+
28
+ ## [0.2.0] - 2026-03-05
29
+
30
+ ### Added
31
+
32
+ - Facebook Live Video settings: `status`, `privacy`, `content_category`, `game_id`,
33
+ `save_vod`, `published`, `stop_on_delete_stream`
34
+ - All settings configurable via plugin config and overridable via named profiles
35
+
36
+ ## [0.1.0] - 2026-03-04
37
+
38
+ ### Added
39
+
40
+ - Initial plugin scaffolding with `MetaPlugin` class
41
+ - Token-based auth module (`auth.py`) with file-based Page Access Token
42
+ - Facebook Live Video creation (`livestream.py`) via Graph API
43
+ - `ON_GAME_INIT` hook handler — creates Facebook Live Video, writes URL to shared context
44
+ - Plugin config schema with `page_access_token_file`, `page_id`, `graph_api_version` fields
45
+ - 100% line + branch test coverage
@@ -0,0 +1,26 @@
1
+ PLUGIN_PKG := reeln_meta_plugin
2
+
3
+ .PHONY: dev-install reeln-install test lint format check
4
+
5
+ VENV := .venv/bin
6
+
7
+ dev-install:
8
+ uv venv --clear
9
+ uv pip install -e ../reeln-cli
10
+ uv pip install -e ".[dev]"
11
+
12
+ reeln-install:
13
+ uv pip install --python ../reeln-cli/.venv/bin/python -e .
14
+
15
+ test:
16
+ $(VENV)/python -m pytest tests/ -n auto --cov=$(PLUGIN_PKG) --cov-branch --cov-fail-under=100 -q
17
+
18
+ lint:
19
+ $(VENV)/ruff check .
20
+
21
+ format:
22
+ $(VENV)/ruff format .
23
+
24
+ check: lint
25
+ $(VENV)/mypy $(PLUGIN_PKG)/
26
+ $(MAKE) test
@@ -0,0 +1,173 @@
1
+ Metadata-Version: 2.4
2
+ Name: reeln-plugin-meta
3
+ Version: 0.4.0
4
+ Summary: reeln-cli plugin for Meta platform integration (Facebook Live, Instagram, Threads)
5
+ Project-URL: Homepage, https://streamn.dad
6
+ Project-URL: Repository, https://github.com/StreamnDad/reeln-plugin-meta
7
+ Project-URL: Changelog, https://github.com/StreamnDad/reeln-plugin-meta/blob/main/CHANGELOG.md
8
+ Project-URL: Issues, https://github.com/StreamnDad/reeln-plugin-meta/issues
9
+ License-Expression: AGPL-3.0-only
10
+ Requires-Python: >=3.11
11
+ Provides-Extra: dev
12
+ Requires-Dist: mypy; extra == 'dev'
13
+ Requires-Dist: pytest; extra == 'dev'
14
+ Requires-Dist: pytest-cov; extra == 'dev'
15
+ Requires-Dist: pytest-xdist; extra == 'dev'
16
+ Requires-Dist: ruff; extra == 'dev'
17
+ Description-Content-Type: text/markdown
18
+
19
+ # reeln-plugin-meta
20
+
21
+ A [reeln-cli](https://github.com/StreamnDad/reeln-cli) plugin for Meta platform integration (Facebook Live, Instagram, Threads).
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ pip install reeln-plugin-meta
27
+ ```
28
+
29
+ Or for development:
30
+
31
+ ```bash
32
+ git clone https://github.com/StreamnDad/reeln-plugin-meta
33
+ cd reeln-plugin-meta
34
+ make dev-install
35
+ ```
36
+
37
+ ## Features
38
+
39
+ - **Facebook Live Video** — creates a live video on your Facebook Page during `ON_GAME_INIT`
40
+ - Writes the livestream embed URL to `context.shared["livestreams"]["meta"]`
41
+ - All features are opt-in via boolean feature flags (default `false`)
42
+
43
+ ## Facebook Developer Setup
44
+
45
+ ### 1. Create a Facebook Developer Account
46
+
47
+ Go to [developers.facebook.com](https://developers.facebook.com/) and register as a developer.
48
+
49
+ ### 2. Create an App
50
+
51
+ 1. Go to **My Apps** → **Create App**
52
+ 2. Select a use case (e.g. **Other** → **Business**)
53
+ 3. Choose **Business** app type
54
+ 4. Fill in app name, contact email, and select a Business portfolio
55
+ 5. Click **Create App**
56
+
57
+ ### 3. Get a Page Access Token
58
+
59
+ 1. Go to the [Graph API Explorer](https://developers.facebook.com/tools/explorer/)
60
+ 2. Select your app from the **Meta App** dropdown
61
+ 3. Click **Generate Access Token**
62
+ 4. Grant the following permissions:
63
+ - `pages_show_list`
64
+ - `pages_manage_posts`
65
+ - `pages_read_engagement`
66
+ - `publish_video`
67
+ 5. Select your Page from the **User or Page** dropdown
68
+ 6. Copy the **Page Access Token**
69
+
70
+ > **Note:** The default token expires in ~1 hour. For a long-lived token
71
+ > (60 days), exchange it via the
72
+ > [Access Token Debugger](https://developers.facebook.com/tools/debug/accesstoken/)
73
+ > or the token exchange endpoint:
74
+ > ```
75
+ > GET /oauth/access_token?grant_type=fb_exchange_token
76
+ > &client_id=APP_ID&client_secret=APP_SECRET
77
+ > &fb_exchange_token=SHORT_LIVED_TOKEN
78
+ > ```
79
+
80
+ ### 4. Save the Token to a File
81
+
82
+ ```bash
83
+ mkdir -p secrets
84
+ echo "YOUR_PAGE_ACCESS_TOKEN" > secrets/meta_page_token.txt
85
+ ```
86
+
87
+ ### 5. Get Your Page ID
88
+
89
+ Find your Page ID in **Page Settings → About → Page ID**, or query it via the API:
90
+
91
+ ```bash
92
+ curl "https://graph.facebook.com/v24.0/me?access_token=YOUR_TOKEN"
93
+ ```
94
+
95
+ ### 6. Configure the Plugin
96
+
97
+ ```bash
98
+ reeln config set meta.page_access_token_file ./secrets/meta_page_token.txt
99
+ reeln config set meta.page_id YOUR_PAGE_ID
100
+ reeln config set meta.create_livestream true
101
+ ```
102
+
103
+ Or edit your reeln config JSON directly:
104
+
105
+ ```json
106
+ {
107
+ "plugins": {
108
+ "enabled": ["meta"],
109
+ "settings": {
110
+ "meta": {
111
+ "page_access_token_file": "./secrets/meta_page_token.txt",
112
+ "page_id": "123456789",
113
+ "create_livestream": true
114
+ }
115
+ }
116
+ }
117
+ }
118
+ ```
119
+
120
+ ### 7. App Review
121
+
122
+ The `publish_video` permission may require App Review for production use.
123
+ During development, you can use the token with your own Pages without review.
124
+
125
+ ## Configuration
126
+
127
+ ### Feature Flags
128
+
129
+ Each capability is gated behind a boolean flag (default `false`):
130
+
131
+ | Field | Default | Description |
132
+ |---|---|---|
133
+ | `create_livestream` | `false` | Enable Facebook Live Video creation on `ON_GAME_INIT` |
134
+ | `dry_run` | `false` | Log API calls without executing them |
135
+
136
+ ### Required Settings
137
+
138
+ | Field | Type | Description |
139
+ |---|---|---|
140
+ | `page_access_token_file` | str | Path to Facebook Page access token file |
141
+ | `page_id` | str | Facebook Page ID |
142
+
143
+ ### Livestream Settings
144
+
145
+ | Field | Type | Default | Description |
146
+ |---|---|---|---|
147
+ | `graph_api_version` | str | `v24.0` | Graph API version |
148
+ | `status` | str | `LIVE_NOW` | Broadcast status (`LIVE_NOW` or `UNPUBLISHED`) |
149
+ | `privacy` | str | `EVERYONE` | Privacy setting (`EVERYONE` or `SELF`) |
150
+ | `content_category` | str | `SPORTS` | Content category (`SPORTS`, `VIDEO_GAMING`, etc.) |
151
+ | `game_id` | str | `""` | Facebook game ID to tag the broadcast with |
152
+ | `save_vod` | bool | `true` | Save a VOD recording after broadcast ends |
153
+ | `published` | bool | `true` | Publish VOD to Page timeline after broadcast ends |
154
+ | `stop_on_delete_stream` | bool | `false` | Auto-end broadcast when RTMP stream disconnects |
155
+
156
+ All settings can be overridden per [named profile](https://reeln-cli.readthedocs.io/en/latest/guide/configuration.html#named-profiles).
157
+ For example, a `config.testing.json` profile could set `"privacy": "SELF"` for test broadcasts
158
+ while your default config stays `"EVERYONE"` for game day.
159
+
160
+ ## Development
161
+
162
+ ```bash
163
+ make dev-install # uv venv + editable install with dev deps
164
+ make reeln-install # install into sibling reeln-cli venv
165
+ make test # pytest with 100% coverage
166
+ make lint # ruff check
167
+ make format # ruff format
168
+ make check # lint + mypy + test
169
+ ```
170
+
171
+ ## License
172
+
173
+ AGPL-3.0-only
@@ -0,0 +1,155 @@
1
+ # reeln-plugin-meta
2
+
3
+ A [reeln-cli](https://github.com/StreamnDad/reeln-cli) plugin for Meta platform integration (Facebook Live, Instagram, Threads).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install reeln-plugin-meta
9
+ ```
10
+
11
+ Or for development:
12
+
13
+ ```bash
14
+ git clone https://github.com/StreamnDad/reeln-plugin-meta
15
+ cd reeln-plugin-meta
16
+ make dev-install
17
+ ```
18
+
19
+ ## Features
20
+
21
+ - **Facebook Live Video** — creates a live video on your Facebook Page during `ON_GAME_INIT`
22
+ - Writes the livestream embed URL to `context.shared["livestreams"]["meta"]`
23
+ - All features are opt-in via boolean feature flags (default `false`)
24
+
25
+ ## Facebook Developer Setup
26
+
27
+ ### 1. Create a Facebook Developer Account
28
+
29
+ Go to [developers.facebook.com](https://developers.facebook.com/) and register as a developer.
30
+
31
+ ### 2. Create an App
32
+
33
+ 1. Go to **My Apps** → **Create App**
34
+ 2. Select a use case (e.g. **Other** → **Business**)
35
+ 3. Choose **Business** app type
36
+ 4. Fill in app name, contact email, and select a Business portfolio
37
+ 5. Click **Create App**
38
+
39
+ ### 3. Get a Page Access Token
40
+
41
+ 1. Go to the [Graph API Explorer](https://developers.facebook.com/tools/explorer/)
42
+ 2. Select your app from the **Meta App** dropdown
43
+ 3. Click **Generate Access Token**
44
+ 4. Grant the following permissions:
45
+ - `pages_show_list`
46
+ - `pages_manage_posts`
47
+ - `pages_read_engagement`
48
+ - `publish_video`
49
+ 5. Select your Page from the **User or Page** dropdown
50
+ 6. Copy the **Page Access Token**
51
+
52
+ > **Note:** The default token expires in ~1 hour. For a long-lived token
53
+ > (60 days), exchange it via the
54
+ > [Access Token Debugger](https://developers.facebook.com/tools/debug/accesstoken/)
55
+ > or the token exchange endpoint:
56
+ > ```
57
+ > GET /oauth/access_token?grant_type=fb_exchange_token
58
+ > &client_id=APP_ID&client_secret=APP_SECRET
59
+ > &fb_exchange_token=SHORT_LIVED_TOKEN
60
+ > ```
61
+
62
+ ### 4. Save the Token to a File
63
+
64
+ ```bash
65
+ mkdir -p secrets
66
+ echo "YOUR_PAGE_ACCESS_TOKEN" > secrets/meta_page_token.txt
67
+ ```
68
+
69
+ ### 5. Get Your Page ID
70
+
71
+ Find your Page ID in **Page Settings → About → Page ID**, or query it via the API:
72
+
73
+ ```bash
74
+ curl "https://graph.facebook.com/v24.0/me?access_token=YOUR_TOKEN"
75
+ ```
76
+
77
+ ### 6. Configure the Plugin
78
+
79
+ ```bash
80
+ reeln config set meta.page_access_token_file ./secrets/meta_page_token.txt
81
+ reeln config set meta.page_id YOUR_PAGE_ID
82
+ reeln config set meta.create_livestream true
83
+ ```
84
+
85
+ Or edit your reeln config JSON directly:
86
+
87
+ ```json
88
+ {
89
+ "plugins": {
90
+ "enabled": ["meta"],
91
+ "settings": {
92
+ "meta": {
93
+ "page_access_token_file": "./secrets/meta_page_token.txt",
94
+ "page_id": "123456789",
95
+ "create_livestream": true
96
+ }
97
+ }
98
+ }
99
+ }
100
+ ```
101
+
102
+ ### 7. App Review
103
+
104
+ The `publish_video` permission may require App Review for production use.
105
+ During development, you can use the token with your own Pages without review.
106
+
107
+ ## Configuration
108
+
109
+ ### Feature Flags
110
+
111
+ Each capability is gated behind a boolean flag (default `false`):
112
+
113
+ | Field | Default | Description |
114
+ |---|---|---|
115
+ | `create_livestream` | `false` | Enable Facebook Live Video creation on `ON_GAME_INIT` |
116
+ | `dry_run` | `false` | Log API calls without executing them |
117
+
118
+ ### Required Settings
119
+
120
+ | Field | Type | Description |
121
+ |---|---|---|
122
+ | `page_access_token_file` | str | Path to Facebook Page access token file |
123
+ | `page_id` | str | Facebook Page ID |
124
+
125
+ ### Livestream Settings
126
+
127
+ | Field | Type | Default | Description |
128
+ |---|---|---|---|
129
+ | `graph_api_version` | str | `v24.0` | Graph API version |
130
+ | `status` | str | `LIVE_NOW` | Broadcast status (`LIVE_NOW` or `UNPUBLISHED`) |
131
+ | `privacy` | str | `EVERYONE` | Privacy setting (`EVERYONE` or `SELF`) |
132
+ | `content_category` | str | `SPORTS` | Content category (`SPORTS`, `VIDEO_GAMING`, etc.) |
133
+ | `game_id` | str | `""` | Facebook game ID to tag the broadcast with |
134
+ | `save_vod` | bool | `true` | Save a VOD recording after broadcast ends |
135
+ | `published` | bool | `true` | Publish VOD to Page timeline after broadcast ends |
136
+ | `stop_on_delete_stream` | bool | `false` | Auto-end broadcast when RTMP stream disconnects |
137
+
138
+ All settings can be overridden per [named profile](https://reeln-cli.readthedocs.io/en/latest/guide/configuration.html#named-profiles).
139
+ For example, a `config.testing.json` profile could set `"privacy": "SELF"` for test broadcasts
140
+ while your default config stays `"EVERYONE"` for game day.
141
+
142
+ ## Development
143
+
144
+ ```bash
145
+ make dev-install # uv venv + editable install with dev deps
146
+ make reeln-install # install into sibling reeln-cli venv
147
+ make test # pytest with 100% coverage
148
+ make lint # ruff check
149
+ make format # ruff format
150
+ make check # lint + mypy + test
151
+ ```
152
+
153
+ ## License
154
+
155
+ AGPL-3.0-only
@@ -0,0 +1,53 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "reeln-plugin-meta"
7
+ dynamic = ["version"]
8
+ description = "reeln-cli plugin for Meta platform integration (Facebook Live, Instagram, Threads)"
9
+ readme = "README.md"
10
+ license = "AGPL-3.0-only"
11
+ requires-python = ">=3.11"
12
+ dependencies = []
13
+
14
+ [project.urls]
15
+ Homepage = "https://streamn.dad"
16
+ Repository = "https://github.com/StreamnDad/reeln-plugin-meta"
17
+ Changelog = "https://github.com/StreamnDad/reeln-plugin-meta/blob/main/CHANGELOG.md"
18
+ Issues = "https://github.com/StreamnDad/reeln-plugin-meta/issues"
19
+
20
+ [project.optional-dependencies]
21
+ dev = [
22
+ "pytest",
23
+ "pytest-cov",
24
+ "pytest-xdist",
25
+ "ruff",
26
+ "mypy",
27
+ ]
28
+
29
+ [project.entry-points."reeln.plugins"]
30
+ meta = "reeln_meta_plugin:MetaPlugin"
31
+
32
+ [tool.hatch.build.targets.wheel]
33
+ packages = ["reeln_meta_plugin"]
34
+
35
+ [tool.hatch.version]
36
+ path = "reeln_meta_plugin/__init__.py"
37
+
38
+ [tool.ruff]
39
+ target-version = "py311"
40
+ line-length = 120
41
+
42
+ [tool.ruff.lint]
43
+ select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]
44
+
45
+ [tool.mypy]
46
+ strict = true
47
+ python_version = "3.11"
48
+ warn_return_any = true
49
+ warn_unused_configs = true
50
+
51
+ [[tool.mypy.overrides]]
52
+ module = "reeln.*"
53
+ ignore_missing_imports = true
@@ -0,0 +1,9 @@
1
+ """reeln-cli plugin for Meta platform integration (Facebook Live, Instagram, Threads)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __version__ = "0.4.0"
6
+
7
+ from reeln_meta_plugin.plugin import MetaPlugin
8
+
9
+ __all__ = ["MetaPlugin", "__version__"]
@@ -0,0 +1,38 @@
1
+ """Token-based authentication for Meta APIs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from reeln.core.config import data_dir
8
+
9
+
10
+ class AuthError(Exception):
11
+ """Raised when authentication fails."""
12
+
13
+
14
+ def default_token_path() -> Path:
15
+ """Return the default Page Access Token file path."""
16
+ return Path(data_dir() / "meta" / "page_token.txt")
17
+
18
+
19
+ def read_token(path: Path) -> str:
20
+ """Read and validate a token from a file.
21
+
22
+ Args:
23
+ path: Path to the token file.
24
+
25
+ Returns:
26
+ The token string (stripped of whitespace).
27
+
28
+ Raises:
29
+ AuthError: If the file is missing or empty.
30
+ """
31
+ if not path.exists():
32
+ raise AuthError(f"Token file not found: {path}")
33
+
34
+ token = path.read_text().strip()
35
+ if not token:
36
+ raise AuthError(f"Token file is empty: {path}")
37
+
38
+ return token