flashdata-youtube-trainability 0.2.0__tar.gz → 0.2.1__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.
Files changed (14) hide show
  1. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/.gitignore +9 -9
  2. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/LICENSE +21 -21
  3. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/PKG-INFO +17 -17
  4. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/README.md +67 -67
  5. flashdata_youtube_trainability-0.2.1/flashdata_youtube_trainability_cli/__init__.py +1 -0
  6. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/flashdata_youtube_trainability_cli/_capability.py +2 -2
  7. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/flashdata_youtube_trainability_cli/cli.py +201 -201
  8. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/input.schema.json +16 -16
  9. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/pyproject.toml +29 -29
  10. flashdata_youtube_trainability-0.2.0/flashdata_youtube_trainability_cli/__init__.py +0 -1
  11. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/flashdata_youtube_trainability_cli/_client.py +0 -0
  12. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/flashdata_youtube_trainability_cli/_inputs.py +0 -0
  13. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/flashdata_youtube_trainability_cli/_storage.py +0 -0
  14. {flashdata_youtube_trainability-0.2.0 → flashdata_youtube_trainability-0.2.1}/flashdata_youtube_trainability_cli/storage.schema.json +0 -0
@@ -1,9 +1,9 @@
1
- .venv/
2
- __pycache__/
3
- .pytest_cache/
4
- .ruff_cache/
5
- packages/
6
- dist/
7
- evidence/
8
-
9
- publish-dist/
1
+ .venv/
2
+ __pycache__/
3
+ .pytest_cache/
4
+ .ruff_cache/
5
+ packages/
6
+ dist/
7
+ evidence/
8
+
9
+ publish-dist/
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 FlashData contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FlashData contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: flashdata-youtube-trainability
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Record Creative Commons license-label evidence with the FlashData JSON CLI
5
- Project-URL: Homepage, https://flashdata.dev/docs/sources/youtube_trainability
6
- Project-URL: Documentation, https://flashdata.dev/docs/sources/youtube_trainability
7
- Project-URL: Pricing, https://flashdata.dev/pricing
8
- Project-URL: Support, https://flashdata.dev
5
+ Project-URL: Homepage, https://flashdata.dev/docs/sources/youtube_trainability?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task
6
+ Project-URL: Documentation, https://flashdata.dev/docs/sources/youtube_trainability?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task
7
+ Project-URL: Pricing, https://flashdata.dev/pricing?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task
8
+ Project-URL: Support, https://flashdata.dev?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task
9
9
  Project-URL: Source, https://github.com/flashdatadev/flashdata-mcp/tree/main/packages/python-cli
10
10
  Author-email: FlashData <support@flashdata.dev>
11
11
  License-Expression: MIT
@@ -32,13 +32,13 @@ permitted is a license-label signal, not legal training permission or creator th
32
32
  Requires Python 3.10 or newer. [uv installation](https://docs.astral.sh/uv/getting-started/installation/)
33
33
  provides `uvx`, which runs this package in an isolated environment.
34
34
 
35
- 1. [Create a FlashData account](https://flashdata.dev/signup), obtain an API Key and fund Credits.
35
+ 1. [Create a FlashData account](https://flashdata.dev/signup?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task), obtain an API Key and fund Credits.
36
36
  2. Set `FLASHDATA_API_KEY` using your shell or secret manager. The CLI does not accept a key flag
37
- or persist credentials. [Authentication and source documentation](https://flashdata.dev/docs/sources/youtube_trainability).
37
+ or persist credentials. [Authentication and source documentation](https://flashdata.dev/docs/sources/youtube_trainability?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task).
38
38
  3. Run this example after reviewing the input and cost:
39
39
 
40
40
  ```sh
41
- uvx flashdata-youtube-trainability@0.2.0 --video-id dQw4w9WgXcQ --output result.json
41
+ uvx flashdata-youtube-trainability@0.2.1 --video-id dQw4w9WgXcQ --output result.json
42
42
  ```
43
43
 
44
44
  `--output` creates a new file with owner-only permissions where supported and refuses existing
@@ -46,8 +46,8 @@ files before making a paid request. Without it, the full JSON response goes to s
46
46
  go to stderr. Exit 0 means the response was exported, 2 means local input/configuration failure,
47
47
  and 1 means request or output failure. For downloads, exit 0 can describe an unfinished job.
48
48
 
49
- For repeated use, install `uv tool install flashdata-youtube-trainability==0.2.0`; the command name is `flashdata-youtube-trainability`.
50
- Alternatively use `python -m pip install flashdata-youtube-trainability==0.2.0` in your virtual environment.
49
+ For repeated use, install `uv tool install flashdata-youtube-trainability==0.2.1`; the command name is `flashdata-youtube-trainability`.
50
+ Alternatively use `python -m pip install flashdata-youtube-trainability==0.2.1` in your virtual environment.
51
51
 
52
52
  ## Inputs and output
53
53
 
@@ -57,33 +57,33 @@ this package. Google count and locale options remain omitted unless supplied.
57
57
 
58
58
  No additional source options.
59
59
 
60
- Run `uvx flashdata-youtube-trainability@0.2.0 --schema` to inspect all fields, nested filters, allowed values and
60
+ Run `uvx flashdata-youtube-trainability@0.2.1 --schema` to inspect all fields, nested filters, allowed values and
61
61
  defaults without a Key or an API call. `--help` and `--version` are also local-only.
62
62
 
63
63
  The JSON output preserves the API result envelope and optional fields: results[]: videoId and license-label indicator permitted, with available kind/etag; usage.credits.
64
64
  Missing fields remain missing; empty results remain empty. No article text, translated captions,
65
65
  model conclusions, rights grants or keyword volumes are invented. Exact source contracts are
66
- documented [here](https://flashdata.dev/docs/sources/youtube_trainability).
66
+ documented [here](https://flashdata.dev/docs/sources/youtube_trainability?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task).
67
67
 
68
68
  ## Fees and failure handling
69
69
 
70
70
  This MIT-licensed CLI is free to install. FlashData API requests consume paid Credits;
71
- [current pricing](https://flashdata.dev/pricing) applies. Extended YouTube Search has a separate
71
+ [current pricing](https://flashdata.dev/pricing?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task) applies. Extended YouTube Search has a separate
72
72
  rate. Media delivery is billed by delivered volume, and your cloud-storage costs are separate.
73
73
  There is no automatic pagination, retry, polling, scheduled execution or model call.
74
74
 
75
75
  Each HTTP request has a 120-second network timeout (15-second connect timeout) and a 20-MiB response
76
76
  limit. A timeout or failure may occur after a paid request has been accepted. Check Jobs in
77
- the [FlashData console](https://flashdata.dev) before resubmitting. HTTP 401 means check the Key;
77
+ the [FlashData console](https://flashdata.dev?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task) before resubmitting. HTTP 401 means check the Key;
78
78
  402 means insufficient Credits; 429 means rate/quota limit. A partial output file is retained
79
79
  on failure. Do not retry a paid query just because output handling failed.
80
80
 
81
81
  Input values and your API Key are sent to FlashData to perform the request. A completed
82
82
  download-result read may fetch a signed JSON object from the result origin returned by
83
83
  FlashData; the API Key is never sent to that object URL. Only process data appropriate for
84
- your output destination. [Privacy policy](https://flashdata.dev/legal/privacy).
84
+ your output destination. [Privacy policy](https://flashdata.dev/legal/privacy?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task).
85
85
 
86
86
  Source and MIT license are included in the source distribution.
87
87
 
88
- [Source documentation](https://flashdata.dev/docs/sources/youtube_trainability) ·
89
- [Pricing](https://flashdata.dev/pricing) · [Sign up](https://flashdata.dev/signup)
88
+ [Source documentation](https://flashdata.dev/docs/sources/youtube_trainability?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task) ·
89
+ [Pricing](https://flashdata.dev/pricing?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task) · [Sign up](https://flashdata.dev/signup?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task)
@@ -1,67 +1,67 @@
1
- # YouTube License Metadata CLI — FlashData
2
-
3
- Record Creative Commons license-label evidence. This command calls the `youtube_trainability` API and returns JSON for your
4
- shell script, data pipeline or agent tool runner. It does not invoke a language model.
5
-
6
- permitted is a license-label signal, not legal training permission or creator third-party training settings.
7
-
8
- ## Install and run
9
-
10
- Requires Python 3.10 or newer. [uv installation](https://docs.astral.sh/uv/getting-started/installation/)
11
- provides `uvx`, which runs this package in an isolated environment.
12
-
13
- 1. [Create a FlashData account](https://flashdata.dev/signup), obtain an API Key and fund Credits.
14
- 2. Set `FLASHDATA_API_KEY` using your shell or secret manager. The CLI does not accept a key flag
15
- or persist credentials. [Authentication and source documentation](https://flashdata.dev/docs/sources/youtube_trainability).
16
- 3. Run this example after reviewing the input and cost:
17
-
18
- ```sh
19
- uvx flashdata-youtube-trainability@0.2.0 --video-id dQw4w9WgXcQ --output result.json
20
- ```
21
-
22
- `--output` creates a new file with owner-only permissions where supported and refuses existing
23
- files before making a paid request. Without it, the full JSON response goes to stdout. Errors
24
- go to stderr. Exit 0 means the response was exported, 2 means local input/configuration failure,
25
- and 1 means request or output failure. For downloads, exit 0 can describe an unfinished job.
26
-
27
- For repeated use, install `uv tool install flashdata-youtube-trainability==0.2.0`; the command name is `flashdata-youtube-trainability`.
28
- Alternatively use `python -m pip install flashdata-youtube-trainability==0.2.0` in your virtual environment.
29
-
30
- ## Inputs and output
31
-
32
- Use `--video-id` for the primary input. Additional options use
33
- `--options-json` as a JSON object, with strict field/type/range validation. Source is fixed by
34
- this package. Google count and locale options remain omitted unless supplied.
35
-
36
- No additional source options.
37
-
38
- Run `uvx flashdata-youtube-trainability@0.2.0 --schema` to inspect all fields, nested filters, allowed values and
39
- defaults without a Key or an API call. `--help` and `--version` are also local-only.
40
-
41
- The JSON output preserves the API result envelope and optional fields: results[]: videoId and license-label indicator permitted, with available kind/etag; usage.credits.
42
- Missing fields remain missing; empty results remain empty. No article text, translated captions,
43
- model conclusions, rights grants or keyword volumes are invented. Exact source contracts are
44
- documented [here](https://flashdata.dev/docs/sources/youtube_trainability).
45
-
46
- ## Fees and failure handling
47
-
48
- This MIT-licensed CLI is free to install. FlashData API requests consume paid Credits;
49
- [current pricing](https://flashdata.dev/pricing) applies. Extended YouTube Search has a separate
50
- rate. Media delivery is billed by delivered volume, and your cloud-storage costs are separate.
51
- There is no automatic pagination, retry, polling, scheduled execution or model call.
52
-
53
- Each HTTP request has a 120-second network timeout (15-second connect timeout) and a 20-MiB response
54
- limit. A timeout or failure may occur after a paid request has been accepted. Check Jobs in
55
- the [FlashData console](https://flashdata.dev) before resubmitting. HTTP 401 means check the Key;
56
- 402 means insufficient Credits; 429 means rate/quota limit. A partial output file is retained
57
- on failure. Do not retry a paid query just because output handling failed.
58
-
59
- Input values and your API Key are sent to FlashData to perform the request. A completed
60
- download-result read may fetch a signed JSON object from the result origin returned by
61
- FlashData; the API Key is never sent to that object URL. Only process data appropriate for
62
- your output destination. [Privacy policy](https://flashdata.dev/legal/privacy).
63
-
64
- Source and MIT license are included in the source distribution.
65
-
66
- [Source documentation](https://flashdata.dev/docs/sources/youtube_trainability) ·
67
- [Pricing](https://flashdata.dev/pricing) · [Sign up](https://flashdata.dev/signup)
1
+ # YouTube License Metadata CLI — FlashData
2
+
3
+ Record Creative Commons license-label evidence. This command calls the `youtube_trainability` API and returns JSON for your
4
+ shell script, data pipeline or agent tool runner. It does not invoke a language model.
5
+
6
+ permitted is a license-label signal, not legal training permission or creator third-party training settings.
7
+
8
+ ## Install and run
9
+
10
+ Requires Python 3.10 or newer. [uv installation](https://docs.astral.sh/uv/getting-started/installation/)
11
+ provides `uvx`, which runs this package in an isolated environment.
12
+
13
+ 1. [Create a FlashData account](https://flashdata.dev/signup?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task), obtain an API Key and fund Credits.
14
+ 2. Set `FLASHDATA_API_KEY` using your shell or secret manager. The CLI does not accept a key flag
15
+ or persist credentials. [Authentication and source documentation](https://flashdata.dev/docs/sources/youtube_trainability?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task).
16
+ 3. Run this example after reviewing the input and cost:
17
+
18
+ ```sh
19
+ uvx flashdata-youtube-trainability@0.2.1 --video-id dQw4w9WgXcQ --output result.json
20
+ ```
21
+
22
+ `--output` creates a new file with owner-only permissions where supported and refuses existing
23
+ files before making a paid request. Without it, the full JSON response goes to stdout. Errors
24
+ go to stderr. Exit 0 means the response was exported, 2 means local input/configuration failure,
25
+ and 1 means request or output failure. For downloads, exit 0 can describe an unfinished job.
26
+
27
+ For repeated use, install `uv tool install flashdata-youtube-trainability==0.2.1`; the command name is `flashdata-youtube-trainability`.
28
+ Alternatively use `python -m pip install flashdata-youtube-trainability==0.2.1` in your virtual environment.
29
+
30
+ ## Inputs and output
31
+
32
+ Use `--video-id` for the primary input. Additional options use
33
+ `--options-json` as a JSON object, with strict field/type/range validation. Source is fixed by
34
+ this package. Google count and locale options remain omitted unless supplied.
35
+
36
+ No additional source options.
37
+
38
+ Run `uvx flashdata-youtube-trainability@0.2.1 --schema` to inspect all fields, nested filters, allowed values and
39
+ defaults without a Key or an API call. `--help` and `--version` are also local-only.
40
+
41
+ The JSON output preserves the API result envelope and optional fields: results[]: videoId and license-label indicator permitted, with available kind/etag; usage.credits.
42
+ Missing fields remain missing; empty results remain empty. No article text, translated captions,
43
+ model conclusions, rights grants or keyword volumes are invented. Exact source contracts are
44
+ documented [here](https://flashdata.dev/docs/sources/youtube_trainability?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task).
45
+
46
+ ## Fees and failure handling
47
+
48
+ This MIT-licensed CLI is free to install. FlashData API requests consume paid Credits;
49
+ [current pricing](https://flashdata.dev/pricing?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task) applies. Extended YouTube Search has a separate
50
+ rate. Media delivery is billed by delivered volume, and your cloud-storage costs are separate.
51
+ There is no automatic pagination, retry, polling, scheduled execution or model call.
52
+
53
+ Each HTTP request has a 120-second network timeout (15-second connect timeout) and a 20-MiB response
54
+ limit. A timeout or failure may occur after a paid request has been accepted. Check Jobs in
55
+ the [FlashData console](https://flashdata.dev?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task) before resubmitting. HTTP 401 means check the Key;
56
+ 402 means insufficient Credits; 429 means rate/quota limit. A partial output file is retained
57
+ on failure. Do not retry a paid query just because output handling failed.
58
+
59
+ Input values and your API Key are sent to FlashData to perform the request. A completed
60
+ download-result read may fetch a signed JSON object from the result origin returned by
61
+ FlashData; the API Key is never sent to that object URL. Only process data appropriate for
62
+ your output destination. [Privacy policy](https://flashdata.dev/legal/privacy?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task).
63
+
64
+ Source and MIT license are included in the source distribution.
65
+
66
+ [Source documentation](https://flashdata.dev/docs/sources/youtube_trainability?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task) ·
67
+ [Pricing](https://flashdata.dev/pricing?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task) · [Sign up](https://flashdata.dev/signup?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task)
@@ -1,2 +1,2 @@
1
- SOURCE = 'youtube_trainability'
2
- COMMAND = 'flashdata-youtube-trainability'
1
+ SOURCE = 'youtube_trainability'
2
+ COMMAND = 'flashdata-youtube-trainability'
@@ -1,201 +1,201 @@
1
- """CLI entry point shared at build time by fifteen independently named packages."""
2
-
3
- import argparse
4
- import json
5
- import os
6
- import sys
7
- from pathlib import Path
8
- from urllib.parse import urlsplit
9
-
10
- from pydantic import ValidationError
11
-
12
- from . import __version__
13
- from ._client import UNKNOWN_OUTCOME, Client, FlashDataError
14
- from ._inputs import (
15
- DownloadJobInput,
16
- GoogleInput,
17
- YouTubeCaptionsInput,
18
- YouTubeChannelInput,
19
- YouTubeDownloadInput,
20
- YouTubeExtendedSearchInput,
21
- YouTubeMetadataInput,
22
- YouTubeSearchInput,
23
- YouTubeSuggestionsInput,
24
- YouTubeTrainabilityInput,
25
- YouTubeTranscriptInput,
26
- )
27
- from ._storage import storage_config
28
-
29
- CONTRACTS = {
30
- **{
31
- f"google_{kind}": GoogleInput
32
- for kind in ("search", "news", "images", "shopping", "videos", "places")
33
- },
34
- "youtube_search": YouTubeSearchInput,
35
- "youtube_search_extended": YouTubeExtendedSearchInput,
36
- "youtube_metadata": YouTubeMetadataInput,
37
- "youtube_transcript": YouTubeTranscriptInput,
38
- "youtube_captions": YouTubeCaptionsInput,
39
- "youtube_trainability": YouTubeTrainabilityInput,
40
- "youtube_channel": YouTubeChannelInput,
41
- "youtube_suggestions": YouTubeSuggestionsInput,
42
- "youtube_download": YouTubeDownloadInput,
43
- }
44
-
45
-
46
- class Parser(argparse.ArgumentParser):
47
- def error(self, message):
48
- raise FlashDataError("Invalid command arguments. Use --help for supported options.")
49
-
50
-
51
- def parser_for(source, command):
52
- parser = Parser(
53
- prog=command,
54
- description=(
55
- f"Run the {source} FlashData API and export JSON. API calls use paid Credits. "
56
- "Read FLASHDATA_API_KEY from the environment; never pass credentials as arguments."
57
- ),
58
- )
59
- parser.add_argument("--version", action="version", version=f"{command} {__version__}")
60
- parser.add_argument(
61
- "--schema", action="store_true", help="Print the input schema; no API call."
62
- )
63
- parser.add_argument(
64
- "--output", type=Path, help="New JSON file (0600); existing files are refused."
65
- )
66
- primary = (
67
- "handle"
68
- if source == "youtube_channel"
69
- else "query"
70
- if (
71
- source.startswith("google_")
72
- or source in ("youtube_search", "youtube_search_extended", "youtube_suggestions")
73
- )
74
- else "video-id"
75
- )
76
- parser.add_argument("--" + primary, help="Primary query, channel handle, or YouTube ID/URL.")
77
- parser.add_argument(
78
- "--options-json", help="Source options as a JSON object, without credentials."
79
- )
80
- if source == "youtube_download":
81
- parser.add_argument("--operation", choices=["status", "result", "submit"], default="status")
82
- parser.add_argument("--job-id", help="Previously saved job ID for status/result.")
83
- parser.add_argument(
84
- "--allow-submit", action="store_true", help="Permit one paid storage write."
85
- )
86
- return parser
87
-
88
-
89
- def payload_for(source, args, environ):
90
- operation = getattr(args, "operation", "query")
91
- if operation in ("status", "result"):
92
- if args.video_id or args.options_json or args.allow_submit:
93
- raise FlashDataError("Status/result accepts --job-id, without submission inputs.")
94
- return operation, DownloadJobInput(job_id=args.job_id).model_dump()
95
- try:
96
- options = json.loads(args.options_json) if args.options_json is not None else {}
97
- except ValueError:
98
- raise FlashDataError("--options-json must be a JSON object.") from None
99
- if not isinstance(options, dict) or any(
100
- field in options for field in ("source", "query", "video_id", "handle", "storage")
101
- ):
102
- raise FlashDataError(
103
- "Use dedicated primary inputs; source is fixed and secrets use env vars."
104
- )
105
- values = dict(options)
106
- for primary in ("query", "video_id", "handle"):
107
- value = getattr(args, primary, None)
108
- if value is not None:
109
- values[primary] = value
110
- data = CONTRACTS[source].model_validate(values).model_dump(exclude_none=True, by_alias=True)
111
- primary = next(key for key in ("query", "video_id", "handle") if key in data)
112
- payload = {"source": source, primary: data.pop(primary), "params": data}
113
- if operation == "submit":
114
- if args.job_id or not args.allow_submit:
115
- raise FlashDataError(
116
- "New delivery requires --allow-submit; saved jobs use status/result."
117
- )
118
- storage = storage_config(environ.get("FLASHDATA_DOWNLOAD_STORAGE", ""))
119
- endpoint = storage.get("endpoint_url")
120
- if endpoint:
121
- url = urlsplit(endpoint)
122
- if (
123
- url.scheme != "https"
124
- or not url.hostname
125
- or url.username
126
- or url.password
127
- or url.query
128
- or url.fragment
129
- ):
130
- raise FlashDataError("Storage endpoint must be an HTTPS URL without credentials.")
131
- payload["params"]["storage"] = storage
132
- return operation, payload
133
-
134
-
135
- def run(
136
- source, command, argv=None, *, environ=None, stdout=None, stderr=None, client_factory=Client
137
- ):
138
- environ = os.environ if environ is None else environ
139
- stdout = sys.stdout if stdout is None else stdout
140
- stderr = sys.stderr if stderr is None else stderr
141
- output = None
142
- request_started = False
143
- output_complete = False
144
- try:
145
- args = parser_for(source, command).parse_args(argv)
146
- if args.schema:
147
- stdout.write(json.dumps(CONTRACTS[source].model_json_schema(), indent=2) + "\n")
148
- return 0
149
- operation, payload = payload_for(source, args, environ)
150
- key = environ.get("FLASHDATA_API_KEY", "").strip()
151
- if not key or any(ord(c) < 32 or ord(c) == 127 for c in key):
152
- raise FlashDataError("Set a valid FLASHDATA_API_KEY environment variable.")
153
- if args.output:
154
- # Reserve the new path before spending Credits, without replacing user files.
155
- fd = os.open(args.output, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
156
- output = os.fdopen(fd, "w", encoding="utf-8")
157
- client = client_factory(key)
158
- request_started = True
159
- result = (
160
- client.query(payload)
161
- if operation == "query"
162
- else client.submit(payload)
163
- if operation == "submit"
164
- else client.status(payload["job_id"])
165
- if operation == "status"
166
- else client.result(payload["job_id"])
167
- )
168
- destination = output if output else stdout
169
- destination.write(json.dumps(result, ensure_ascii=False, allow_nan=False, indent=2) + "\n")
170
- destination.flush()
171
- output_complete = True
172
- return 0
173
- except ValidationError:
174
- stderr.write("Invalid source input. See --schema for fields, types, ranges and defaults.\n")
175
- return 2
176
- except FlashDataError as error:
177
- stderr.write(str(error) + "\n")
178
- return 1 if request_started else 2
179
- except (OSError, ValueError, TypeError):
180
- stderr.write(
181
- (
182
- "Could not save the response. " + UNKNOWN_OUTCOME
183
- if request_started
184
- else "Could not prepare output or inputs. Check the new output path."
185
- )
186
- + "\n"
187
- )
188
- return 1 if request_started else 2
189
- finally:
190
- if output:
191
- output.close()
192
- if not output_complete:
193
- stderr.write(
194
- "The newly reserved output file is incomplete; check Jobs before retrying.\n"
195
- )
196
-
197
-
198
- def main():
199
- from ._capability import COMMAND, SOURCE
200
-
201
- raise SystemExit(run(SOURCE, COMMAND))
1
+ """CLI entry point shared at build time by fifteen independently named packages."""
2
+
3
+ import argparse
4
+ import json
5
+ import os
6
+ import sys
7
+ from pathlib import Path
8
+ from urllib.parse import urlsplit
9
+
10
+ from pydantic import ValidationError
11
+
12
+ from . import __version__
13
+ from ._client import UNKNOWN_OUTCOME, Client, FlashDataError
14
+ from ._inputs import (
15
+ DownloadJobInput,
16
+ GoogleInput,
17
+ YouTubeCaptionsInput,
18
+ YouTubeChannelInput,
19
+ YouTubeDownloadInput,
20
+ YouTubeExtendedSearchInput,
21
+ YouTubeMetadataInput,
22
+ YouTubeSearchInput,
23
+ YouTubeSuggestionsInput,
24
+ YouTubeTrainabilityInput,
25
+ YouTubeTranscriptInput,
26
+ )
27
+ from ._storage import storage_config
28
+
29
+ CONTRACTS = {
30
+ **{
31
+ f"google_{kind}": GoogleInput
32
+ for kind in ("search", "news", "images", "shopping", "videos", "places")
33
+ },
34
+ "youtube_search": YouTubeSearchInput,
35
+ "youtube_search_extended": YouTubeExtendedSearchInput,
36
+ "youtube_metadata": YouTubeMetadataInput,
37
+ "youtube_transcript": YouTubeTranscriptInput,
38
+ "youtube_captions": YouTubeCaptionsInput,
39
+ "youtube_trainability": YouTubeTrainabilityInput,
40
+ "youtube_channel": YouTubeChannelInput,
41
+ "youtube_suggestions": YouTubeSuggestionsInput,
42
+ "youtube_download": YouTubeDownloadInput,
43
+ }
44
+
45
+
46
+ class Parser(argparse.ArgumentParser):
47
+ def error(self, message):
48
+ raise FlashDataError("Invalid command arguments. Use --help for supported options.")
49
+
50
+
51
+ def parser_for(source, command):
52
+ parser = Parser(
53
+ prog=command,
54
+ description=(
55
+ f"Run the {source} FlashData API and export JSON. API calls use paid Credits. "
56
+ "Read FLASHDATA_API_KEY from the environment; never pass credentials as arguments."
57
+ ),
58
+ )
59
+ parser.add_argument("--version", action="version", version=f"{command} {__version__}")
60
+ parser.add_argument(
61
+ "--schema", action="store_true", help="Print the input schema; no API call."
62
+ )
63
+ parser.add_argument(
64
+ "--output", type=Path, help="New JSON file (0600); existing files are refused."
65
+ )
66
+ primary = (
67
+ "handle"
68
+ if source == "youtube_channel"
69
+ else "query"
70
+ if (
71
+ source.startswith("google_")
72
+ or source in ("youtube_search", "youtube_search_extended", "youtube_suggestions")
73
+ )
74
+ else "video-id"
75
+ )
76
+ parser.add_argument("--" + primary, help="Primary query, channel handle, or YouTube ID/URL.")
77
+ parser.add_argument(
78
+ "--options-json", help="Source options as a JSON object, without credentials."
79
+ )
80
+ if source == "youtube_download":
81
+ parser.add_argument("--operation", choices=["status", "result", "submit"], default="status")
82
+ parser.add_argument("--job-id", help="Previously saved job ID for status/result.")
83
+ parser.add_argument(
84
+ "--allow-submit", action="store_true", help="Permit one paid storage write."
85
+ )
86
+ return parser
87
+
88
+
89
+ def payload_for(source, args, environ):
90
+ operation = getattr(args, "operation", "query")
91
+ if operation in ("status", "result"):
92
+ if args.video_id or args.options_json or args.allow_submit:
93
+ raise FlashDataError("Status/result accepts --job-id, without submission inputs.")
94
+ return operation, DownloadJobInput(job_id=args.job_id).model_dump()
95
+ try:
96
+ options = json.loads(args.options_json) if args.options_json is not None else {}
97
+ except ValueError:
98
+ raise FlashDataError("--options-json must be a JSON object.") from None
99
+ if not isinstance(options, dict) or any(
100
+ field in options for field in ("source", "query", "video_id", "handle", "storage")
101
+ ):
102
+ raise FlashDataError(
103
+ "Use dedicated primary inputs; source is fixed and secrets use env vars."
104
+ )
105
+ values = dict(options)
106
+ for primary in ("query", "video_id", "handle"):
107
+ value = getattr(args, primary, None)
108
+ if value is not None:
109
+ values[primary] = value
110
+ data = CONTRACTS[source].model_validate(values).model_dump(exclude_none=True, by_alias=True)
111
+ primary = next(key for key in ("query", "video_id", "handle") if key in data)
112
+ payload = {"source": source, primary: data.pop(primary), "params": data}
113
+ if operation == "submit":
114
+ if args.job_id or not args.allow_submit:
115
+ raise FlashDataError(
116
+ "New delivery requires --allow-submit; saved jobs use status/result."
117
+ )
118
+ storage = storage_config(environ.get("FLASHDATA_DOWNLOAD_STORAGE", ""))
119
+ endpoint = storage.get("endpoint_url")
120
+ if endpoint:
121
+ url = urlsplit(endpoint)
122
+ if (
123
+ url.scheme != "https"
124
+ or not url.hostname
125
+ or url.username
126
+ or url.password
127
+ or url.query
128
+ or url.fragment
129
+ ):
130
+ raise FlashDataError("Storage endpoint must be an HTTPS URL without credentials.")
131
+ payload["params"]["storage"] = storage
132
+ return operation, payload
133
+
134
+
135
+ def run(
136
+ source, command, argv=None, *, environ=None, stdout=None, stderr=None, client_factory=Client
137
+ ):
138
+ environ = os.environ if environ is None else environ
139
+ stdout = sys.stdout if stdout is None else stdout
140
+ stderr = sys.stderr if stderr is None else stderr
141
+ output = None
142
+ request_started = False
143
+ output_complete = False
144
+ try:
145
+ args = parser_for(source, command).parse_args(argv)
146
+ if args.schema:
147
+ stdout.write(json.dumps(CONTRACTS[source].model_json_schema(), indent=2) + "\n")
148
+ return 0
149
+ operation, payload = payload_for(source, args, environ)
150
+ key = environ.get("FLASHDATA_API_KEY", "").strip()
151
+ if not key or any(ord(c) < 32 or ord(c) == 127 for c in key):
152
+ raise FlashDataError("Set a valid FLASHDATA_API_KEY environment variable.")
153
+ if args.output:
154
+ # Reserve the new path before spending Credits, without replacing user files.
155
+ fd = os.open(args.output, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
156
+ output = os.fdopen(fd, "w", encoding="utf-8")
157
+ client = client_factory(key)
158
+ request_started = True
159
+ result = (
160
+ client.query(payload)
161
+ if operation == "query"
162
+ else client.submit(payload)
163
+ if operation == "submit"
164
+ else client.status(payload["job_id"])
165
+ if operation == "status"
166
+ else client.result(payload["job_id"])
167
+ )
168
+ destination = output if output else stdout
169
+ destination.write(json.dumps(result, ensure_ascii=False, allow_nan=False, indent=2) + "\n")
170
+ destination.flush()
171
+ output_complete = True
172
+ return 0
173
+ except ValidationError:
174
+ stderr.write("Invalid source input. See --schema for fields, types, ranges and defaults.\n")
175
+ return 2
176
+ except FlashDataError as error:
177
+ stderr.write(str(error) + "\n")
178
+ return 1 if request_started else 2
179
+ except (OSError, ValueError, TypeError):
180
+ stderr.write(
181
+ (
182
+ "Could not save the response. " + UNKNOWN_OUTCOME
183
+ if request_started
184
+ else "Could not prepare output or inputs. Check the new output path."
185
+ )
186
+ + "\n"
187
+ )
188
+ return 1 if request_started else 2
189
+ finally:
190
+ if output:
191
+ output.close()
192
+ if not output_complete:
193
+ stderr.write(
194
+ "The newly reserved output file is incomplete; check Jobs before retrying.\n"
195
+ )
196
+
197
+
198
+ def main():
199
+ from ._capability import COMMAND, SOURCE
200
+
201
+ raise SystemExit(run(SOURCE, COMMAND))
@@ -1,16 +1,16 @@
1
- {
2
- "additionalProperties": false,
3
- "description": "Inspect license labels; this does not establish training permission.",
4
- "properties": {
5
- "video_id": {
6
- "description": "11-character YouTube video ID or a YouTube video URL.",
7
- "title": "Video Id",
8
- "type": "string"
9
- }
10
- },
11
- "required": [
12
- "video_id"
13
- ],
14
- "title": "YouTubeTrainabilityInput",
15
- "type": "object"
16
- }
1
+ {
2
+ "additionalProperties": false,
3
+ "description": "Inspect license labels; this does not establish training permission.",
4
+ "properties": {
5
+ "video_id": {
6
+ "description": "11-character YouTube video ID or a YouTube video URL.",
7
+ "title": "Video Id",
8
+ "type": "string"
9
+ }
10
+ },
11
+ "required": [
12
+ "video_id"
13
+ ],
14
+ "title": "YouTubeTrainabilityInput",
15
+ "type": "object"
16
+ }
@@ -1,29 +1,29 @@
1
- [build-system]
2
- requires = ["hatchling>=1.27,<2"]
3
- build-backend = "hatchling.build"
4
-
5
- [project]
6
- name = "flashdata-youtube-trainability"
7
- version = "0.2.0"
8
- description = "Record Creative Commons license-label evidence with the FlashData JSON CLI"
9
- readme = "README.md"
10
- requires-python = ">=3.10"
11
- license = "MIT"
12
- license-files = ["LICENSE"]
13
- authors = [{name = "FlashData", email = "support@flashdata.dev"}]
14
- keywords = ["youtube-trainability", "cli", "json", "uvx", "flashdata"]
15
- classifiers = ["Intended Audience :: Developers", "Programming Language :: Python :: 3", "Environment :: Console"]
16
- dependencies = ["httpx>=0.28.1,<1", "pydantic>=2.7.4,<3", "jsonschema>=4.23,<5"]
17
-
18
- [project.scripts]
19
- flashdata-youtube-trainability = "flashdata_youtube_trainability_cli.cli:main"
20
-
21
- [project.urls]
22
- Homepage = "https://flashdata.dev/docs/sources/youtube_trainability"
23
- Documentation = "https://flashdata.dev/docs/sources/youtube_trainability"
24
- Pricing = "https://flashdata.dev/pricing"
25
- Support = "https://flashdata.dev"
26
- Source = "https://github.com/flashdatadev/flashdata-mcp/tree/main/packages/python-cli"
27
-
28
- [tool.hatch.build.targets.wheel]
29
- packages = ["flashdata_youtube_trainability_cli"]
1
+ [build-system]
2
+ requires = ["hatchling>=1.27,<2"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "flashdata-youtube-trainability"
7
+ version = "0.2.1"
8
+ description = "Record Creative Commons license-label evidence with the FlashData JSON CLI"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{name = "FlashData", email = "support@flashdata.dev"}]
14
+ keywords = ["youtube-trainability", "cli", "json", "uvx", "flashdata"]
15
+ classifiers = ["Intended Audience :: Developers", "Programming Language :: Python :: 3", "Environment :: Console"]
16
+ dependencies = ["httpx>=0.28.1,<1", "pydantic>=2.7.4,<3", "jsonschema>=4.23,<5"]
17
+
18
+ [project.scripts]
19
+ flashdata-youtube-trainability = "flashdata_youtube_trainability_cli.cli:main"
20
+
21
+ [project.urls]
22
+ Homepage = "https://flashdata.dev/docs/sources/youtube_trainability?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task"
23
+ Documentation = "https://flashdata.dev/docs/sources/youtube_trainability?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task"
24
+ Pricing = "https://flashdata.dev/pricing?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task"
25
+ Support = "https://flashdata.dev?utm_source=pypi&utm_medium=integration&utm_campaign=intent_gtm_2026q4&utm_content=youtube_trainability-task"
26
+ Source = "https://github.com/flashdatadev/flashdata-mcp/tree/main/packages/python-cli"
27
+
28
+ [tool.hatch.build.targets.wheel]
29
+ packages = ["flashdata_youtube_trainability_cli"]