crawlora-youtube 0.1.9 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7b86318f6f5aa34512871e98863158c516f76fe3cc9c2c9665cb6351d9e526b
4
- data.tar.gz: 5f90536e183860fa7d4d3e0123c1490749520c22262542c441247fd8624d8b62
3
+ metadata.gz: cc1fbd6d037db489ecc3dd822f3381febd8afe13a3ddcbaa10b589cc414f4a80
4
+ data.tar.gz: 03d933f5b9d21de4ff68fcf59f5b0e63fc77829affd85c36e8703fb138f954dd
5
5
  SHA512:
6
- metadata.gz: 3be734757bff9701840f16054f7a377f20326532d8444a4c84249559c434ea214018028ad30730ffc31d2330c69b53391f349d251d04334acf3596d07fc2fb70
7
- data.tar.gz: 2c9ed0b2af2d63ab9b1f7d2a473aac588ee526819d2791a16685fe9f813bd0d5b8f1bfb3a6b41441a288c5f756b9d9c7a032d1490f5a2a125ee1a88e520a4f6d
6
+ metadata.gz: 66d0f70c59ca171af2115dcbaa79b42a41cd25bcda5de18eab2fb53e6483cea287e074700fd3dd19ff35b39506a0bdece20054fc939a3c282c88b4cd69586282
7
+ data.tar.gz: dc12f263b6bb8dd4eab6c1160b53c849b42871266a7e52a0ab5aea6c12dba6c25cbced56a7bce7a38fcc786d40fb6cacd8b6855baabb192e2072777c597603c3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.9
3
+ ## 0.3.0
4
4
 
5
5
  - Initial focused YouTube Ruby client for Crawlora's hosted API.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Crawlora YouTube API client for Ruby (`crawlora-youtube`)
2
2
 
3
- This Ruby gem calls Crawlora's hosted YouTube API at `https://api.crawlora.net/api/v1`. It exposes 14 endpoints covering search, channels, videos, playlists, comments, captions, and transcripts; it does not call or scrape YouTube directly. Requests require your Crawlora API key and use your account's service plan.
3
+ This Ruby gem calls Crawlora's hosted YouTube API at `https://api.crawlora.net/api/v1`. It exposes 15 endpoints covering search, channels, videos, playlists, comments, captions, and transcripts; it does not call or scrape YouTube directly. Requests require your Crawlora API key and use your account's service plan.
4
4
 
5
5
  ## Install
6
6
 
@@ -20,7 +20,7 @@ puts result
20
20
  client.close
21
21
  ```
22
22
 
23
- Use an operation-specific method for normal calls. `request(operation_id, params = {}, response_type: :auto)` is available for every operation. `response_type: :text` returns raw response text. This gem includes 14 API operations.
23
+ Use an operation-specific method for normal calls. `request(operation_id, params = {}, response_type: :auto)` is available for every operation. `response_type: :text` returns raw response text. This gem includes 15 API operations.
24
24
 
25
25
  ```ruby
26
26
  client = Crawlora::Youtube::Client.new(api_key: ENV.fetch("CRAWLORA_API_KEY"), timeout: 30)
@@ -41,7 +41,8 @@ Browse every route included in this gem. The [endpoint reference](https://github
41
41
  | `GET` | `/youtube/channel/{id}/search` | `youtube-channel-search` | Search within a YouTube channel |
42
42
  | `GET` | `/youtube/channel/{id}/shorts` | `youtube-channel-shorts` | Retrieve the shorts tab for a YouTube channel |
43
43
  | `GET` | `/youtube/channel/{id}/videos` | `youtube-channel-videos` | Retrieve the videos tab for a YouTube channel |
44
- | `GET` | `/youtube/comments/{id}` | `youtube-comments` | Retrieve video comments (top-level & replies) |
44
+ | `GET` | `/youtube/comments/{id}` | `youtube-comments` | Retrieve top-level video comments |
45
+ | `GET` | `/youtube/comments/{id}/replies` | `youtube-comment-replies` | Retrieve replies to one YouTube comment |
45
46
  | `GET` | `/youtube/playlist/{id}` | `youtube-playlist` | Retrieve playlist metadata and items |
46
47
  | `GET` | `/youtube/profile/{id}` | `youtube-profile` | Retrieve channel profile |
47
48
  | `GET` | `/youtube/search` | `youtube-search` | Search YouTube |
@@ -19,17 +19,17 @@ module Crawlora
19
19
  end
20
20
 
21
21
  OPERATIONS = JSON.parse(<<~'JSON').freeze
22
- {"youtube-captions": {"bodyParam": null, "bodyRequired": false, "id": "youtube-captions", "method": "GET", "params": [{"description": "YouTube video ID (11-character code)", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "YbJOTdZBX1g"}, {"default": "en", "description": "Caption language code (ISO 639-1), defaults to **en**", "in": "query", "name": "lang", "type": "string"}], "path": "/youtube/captions/{id}", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "lang", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-channel-playlists": {"bodyParam": null, "bodyRequired": false, "id": "youtube-channel-playlists", "method": "GET", "params": [{"description": "Channel ID, @handle, /c path, /user path, or full YouTube channel URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "UCXZCJLdBC09xxGZ6gcdrc6A"}, {"description": "Pagination token returned by a previous request", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/channel/{id}/playlists", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-channel-search": {"bodyParam": null, "bodyRequired": false, "id": "youtube-channel-search", "method": "GET", "params": [{"description": "Channel ID, @handle, /c path, /user path, or full YouTube channel URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "UCXZCJLdBC09xxGZ6gcdrc6A"}, {"description": "Search query", "in": "query", "name": "q", "required": true, "type": "string", "x-example": "gpt"}, {"description": "Pagination token returned by a previous request", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/channel/{id}/search", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "q", "required": true, "type": "string"}, {"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-channel-shorts": {"bodyParam": null, "bodyRequired": false, "id": "youtube-channel-shorts", "method": "GET", "params": [{"description": "Channel ID, @handle, /c path, /user path, or full YouTube channel URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "UCXZCJLdBC09xxGZ6gcdrc6A"}], "path": "/youtube/channel/{id}/shorts", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [], "security": ["ApiKeyAuth"]}, "youtube-channel-videos": {"bodyParam": null, "bodyRequired": false, "id": "youtube-channel-videos", "method": "GET", "params": [{"description": "Channel ID, @handle, /c path, /user path, or full YouTube channel URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "UCXZCJLdBC09xxGZ6gcdrc6A"}, {"description": "Pagination token returned by a previous request", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/channel/{id}/videos", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-comments": {"bodyParam": null, "bodyRequired": false, "id": "youtube-comments", "method": "GET", "params": [{"description": "YouTube video ID (11-character code)", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "YbJOTdZBX1g"}, {"description": "Pagination token returned by a previous request, first page if empty", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/comments/{id}", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-playlist": {"bodyParam": null, "bodyRequired": false, "id": "youtube-playlist", "method": "GET", "params": [{"description": "YouTube playlist ID or full playlist URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "PL-szjqIBRvM_aWOj-uXCVm28l-ZZFa4D2"}, {"description": "Pagination token returned by a previous request", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/playlist/{id}", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-profile": {"bodyParam": null, "bodyRequired": false, "id": "youtube-profile", "method": "GET", "params": [{"description": "Channel ID, @handle, /c path, /user path, bare username, or full YouTube channel URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "UCXZCJLdBC09xxGZ6gcdrc6A"}], "path": "/youtube/profile/{id}", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [], "security": ["ApiKeyAuth"]}, "youtube-search": {"bodyParam": null, "bodyRequired": false, "id": "youtube-search", "method": "GET", "params": [{"description": "Search query", "in": "query", "name": "q", "type": "string", "x-example": "gpt"}, {"description": "Alias for q", "in": "query", "name": "search_query", "type": "string", "x-example": "gpt"}, {"description": "Pagination token returned by a previous request", "in": "query", "name": "continuation_token", "type": "string"}, {"description": "Filter by type", "enum": ["video", "shorts", "channel", "playlist", "movie"], "in": "query", "name": "type", "type": "string"}, {"description": "Sort results", "enum": ["relevance", "upload_date", "view_count", "popularity", "rating"], "in": "query", "name": "sort_by", "type": "string"}, {"description": "Filter by upload date", "enum": ["last_hour", "today", "this_week", "this_month", "this_year"], "in": "query", "name": "upload_date", "type": "string"}, {"description": "Filter by duration; short, medium, and long preserve their previous upstream encodings", "enum": ["under_3_minutes", "three_to_20_minutes", "over_20_minutes", "under_3", "three_to_20", "over_20", "short", "medium", "long"], "in": "query", "name": "duration", "type": "string"}, {"description": "Comma-separated feature filters. Allowed values: live, 4k, hd, subtitles, cc, creative_commons, 360, vr180, 3d, hdr, location, purchased", "in": "query", "name": "features", "type": "string", "x-example": "hd,subtitles"}, {"description": "YouTube interface language", "in": "query", "name": "hl", "type": "string", "x-example": "en"}, {"description": "Two-letter YouTube region code", "in": "query", "name": "gl", "type": "string", "x-example": "US"}, {"description": "Raw protobuf-encoded search filter (base64)", "in": "query", "name": "params", "type": "string"}], "path": "/youtube/search", "pathParams": [], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "q", "type": "string"}, {"in": "query", "name": "search_query", "type": "string"}, {"in": "query", "name": "continuation_token", "type": "string"}, {"enum": ["video", "shorts", "channel", "playlist", "movie"], "in": "query", "name": "type", "type": "string"}, {"enum": ["relevance", "upload_date", "view_count", "popularity", "rating"], "in": "query", "name": "sort_by", "type": "string"}, {"enum": ["last_hour", "today", "this_week", "this_month", "this_year"], "in": "query", "name": "upload_date", "type": "string"}, {"enum": ["under_3_minutes", "three_to_20_minutes", "over_20_minutes", "under_3", "three_to_20", "over_20", "short", "medium", "long"], "in": "query", "name": "duration", "type": "string"}, {"in": "query", "name": "features", "type": "string"}, {"in": "query", "name": "hl", "type": "string"}, {"in": "query", "name": "gl", "type": "string"}, {"in": "query", "name": "params", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-suggest": {"bodyParam": null, "bodyRequired": false, "id": "youtube-suggest", "method": "GET", "params": [{"description": "Search query prefix", "in": "query", "name": "q", "required": true, "type": "string", "x-example": "openai"}, {"description": "Suggestions to return; defaults to 10, clamped to 1..20", "in": "query", "maximum": 20, "minimum": 1, "name": "count", "type": "integer", "x-example": 10}, {"description": "YouTube interface language, such as en, de, or pt-BR; defaults to en", "in": "query", "name": "hl", "type": "string", "x-example": "en"}, {"description": "Two-letter YouTube region code; defaults to US", "in": "query", "name": "gl", "type": "string", "x-example": "US"}], "path": "/youtube/suggest", "pathParams": [], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "q", "required": true, "type": "string"}, {"in": "query", "name": "count", "type": "integer"}, {"in": "query", "name": "hl", "type": "string"}, {"in": "query", "name": "gl", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-tag": {"bodyParam": null, "bodyRequired": false, "id": "youtube-tag", "method": "GET", "params": [{"description": "Tag to filter videos", "in": "path", "name": "tag", "required": true, "type": "string", "x-example": "openai"}, {"default": "all", "description": "Result tab to load", "enum": ["all", "shorts"], "in": "query", "name": "type", "type": "string"}, {"description": "Continuation token for pagination, first page if empty", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/tag/{tag}", "pathParams": ["tag"], "produces": ["application/json"], "queryParams": [{"enum": ["all", "shorts"], "in": "query", "name": "type", "type": "string"}, {"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-transcript": {"bodyParam": null, "bodyRequired": false, "id": "youtube-transcript", "method": "GET", "params": [{"description": "YouTube video ID (11-character code)", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "YbJOTdZBX1g"}, {"default": "en", "description": "Preferred transcript language", "in": "query", "name": "lang", "type": "string"}, {"description": "Translate transcript to this language code", "in": "query", "name": "translate_to", "type": "string"}, {"default": "json", "description": "Response format", "enum": ["json", "text", "srt", "vtt"], "in": "query", "name": "format", "type": "string"}, {"default": true, "description": "Include timestamps in the JSON response", "in": "query", "name": "timestamps", "type": "boolean"}], "path": "/youtube/transcript/{id}", "pathParams": ["id"], "produces": ["application/json", "text/plain"], "queryParams": [{"in": "query", "name": "lang", "type": "string"}, {"in": "query", "name": "translate_to", "type": "string"}, {"enum": ["json", "text", "srt", "vtt"], "in": "query", "name": "format", "type": "string"}, {"in": "query", "name": "timestamps", "type": "boolean"}], "security": ["ApiKeyAuth"]}, "youtube-transcript-languages": {"bodyParam": null, "bodyRequired": false, "id": "youtube-transcript-languages", "method": "GET", "params": [{"description": "YouTube video ID (11-character code)", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "YbJOTdZBX1g"}], "path": "/youtube/transcript/{id}/languages", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [], "security": ["ApiKeyAuth"]}, "youtube-video": {"bodyParam": null, "bodyRequired": false, "id": "youtube-video", "method": "GET", "params": [{"description": "YouTube video ID (11-char code)", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "YbJOTdZBX1g"}], "path": "/youtube/video/{id}", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [], "security": ["ApiKeyAuth"]}}
22
+ {"youtube-captions": {"bodyParam": null, "bodyRequired": false, "id": "youtube-captions", "method": "GET", "params": [{"description": "YouTube video ID (11-character code)", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "YbJOTdZBX1g"}, {"default": "en", "description": "Caption language code (ISO 639-1), defaults to **en**", "in": "query", "name": "lang", "type": "string"}], "path": "/youtube/captions/{id}", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "lang", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-channel-playlists": {"bodyParam": null, "bodyRequired": false, "id": "youtube-channel-playlists", "method": "GET", "params": [{"description": "Channel ID, @handle, /c path, /user path, or full YouTube channel URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "UCXZCJLdBC09xxGZ6gcdrc6A"}, {"description": "Pagination token returned by a previous request", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/channel/{id}/playlists", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-channel-search": {"bodyParam": null, "bodyRequired": false, "id": "youtube-channel-search", "method": "GET", "params": [{"description": "Channel ID, @handle, /c path, /user path, or full YouTube channel URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "UCXZCJLdBC09xxGZ6gcdrc6A"}, {"description": "Search query", "in": "query", "name": "q", "required": true, "type": "string", "x-example": "gpt"}, {"description": "Pagination token returned by a previous request", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/channel/{id}/search", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "q", "required": true, "type": "string"}, {"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-channel-shorts": {"bodyParam": null, "bodyRequired": false, "id": "youtube-channel-shorts", "method": "GET", "params": [{"description": "Channel ID, @handle, /c path, /user path, or full YouTube channel URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "UCXZCJLdBC09xxGZ6gcdrc6A"}, {"description": "Opaque pagination token returned by the previous response", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/channel/{id}/shorts", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-channel-videos": {"bodyParam": null, "bodyRequired": false, "id": "youtube-channel-videos", "method": "GET", "params": [{"description": "Channel ID, @handle, /c path, /user path, or full YouTube channel URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "UCXZCJLdBC09xxGZ6gcdrc6A"}, {"description": "Pagination token returned by a previous request", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/channel/{id}/videos", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-comment-replies": {"bodyParam": null, "bodyRequired": false, "id": "youtube-comment-replies", "method": "GET", "params": [{"description": "YouTube video ID (11-character code)", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "YbJOTdZBX1g"}, {"description": "Opaque per-comment reply token from a comment object", "in": "query", "name": "continuation_token", "required": true, "type": "string", "x-example": "COMMENT_REPLIES_TOKEN"}], "path": "/youtube/comments/{id}/replies", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "continuation_token", "required": true, "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-comments": {"bodyParam": null, "bodyRequired": false, "id": "youtube-comments", "method": "GET", "params": [{"description": "YouTube video ID (11-character code)", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "YbJOTdZBX1g"}, {"description": "Opaque pagination token returned by a previous request; pass it for deterministic pagination", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/comments/{id}", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-playlist": {"bodyParam": null, "bodyRequired": false, "id": "youtube-playlist", "method": "GET", "params": [{"description": "YouTube playlist ID or full playlist URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "PL-szjqIBRvM_aWOj-uXCVm28l-ZZFa4D2"}, {"description": "Pagination token returned by a previous request", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/playlist/{id}", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-profile": {"bodyParam": null, "bodyRequired": false, "id": "youtube-profile", "method": "GET", "params": [{"description": "Channel ID, @handle, /c path, /user path, bare username, or full YouTube channel URL", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "UCXZCJLdBC09xxGZ6gcdrc6A"}], "path": "/youtube/profile/{id}", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [], "security": ["ApiKeyAuth"]}, "youtube-search": {"bodyParam": null, "bodyRequired": false, "id": "youtube-search", "method": "GET", "params": [{"description": "Search query", "in": "query", "name": "q", "type": "string", "x-example": "gpt"}, {"description": "Alias for q", "in": "query", "name": "search_query", "type": "string", "x-example": "gpt"}, {"description": "Pagination token returned by a previous request", "in": "query", "name": "continuation_token", "type": "string"}, {"description": "Filter by type", "enum": ["video", "shorts", "channel", "playlist", "movie"], "in": "query", "name": "type", "type": "string"}, {"description": "Sort results", "enum": ["relevance", "upload_date", "view_count", "popularity", "rating"], "in": "query", "name": "sort_by", "type": "string"}, {"description": "Filter by upload date", "enum": ["last_hour", "today", "this_week", "this_month", "this_year"], "in": "query", "name": "upload_date", "type": "string"}, {"description": "Filter by duration; short, medium, and long preserve their previous upstream encodings", "enum": ["under_3_minutes", "three_to_20_minutes", "over_20_minutes", "under_3", "three_to_20", "over_20", "short", "medium", "long"], "in": "query", "name": "duration", "type": "string"}, {"description": "Comma-separated feature filters. Allowed values: live, 4k, hd, subtitles, cc, creative_commons, 360, vr180, 3d, hdr, location, purchased", "in": "query", "name": "features", "type": "string", "x-example": "hd,subtitles"}, {"description": "YouTube interface language", "in": "query", "name": "hl", "type": "string", "x-example": "en"}, {"description": "Two-letter YouTube region code", "in": "query", "name": "gl", "type": "string", "x-example": "US"}, {"description": "Raw protobuf-encoded search filter (base64)", "in": "query", "name": "params", "type": "string"}], "path": "/youtube/search", "pathParams": [], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "q", "type": "string"}, {"in": "query", "name": "search_query", "type": "string"}, {"in": "query", "name": "continuation_token", "type": "string"}, {"enum": ["video", "shorts", "channel", "playlist", "movie"], "in": "query", "name": "type", "type": "string"}, {"enum": ["relevance", "upload_date", "view_count", "popularity", "rating"], "in": "query", "name": "sort_by", "type": "string"}, {"enum": ["last_hour", "today", "this_week", "this_month", "this_year"], "in": "query", "name": "upload_date", "type": "string"}, {"enum": ["under_3_minutes", "three_to_20_minutes", "over_20_minutes", "under_3", "three_to_20", "over_20", "short", "medium", "long"], "in": "query", "name": "duration", "type": "string"}, {"in": "query", "name": "features", "type": "string"}, {"in": "query", "name": "hl", "type": "string"}, {"in": "query", "name": "gl", "type": "string"}, {"in": "query", "name": "params", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-suggest": {"bodyParam": null, "bodyRequired": false, "id": "youtube-suggest", "method": "GET", "params": [{"description": "Search query prefix", "in": "query", "name": "q", "required": true, "type": "string", "x-example": "openai"}, {"description": "Suggestions to return; defaults to 10, clamped to 1..20", "in": "query", "maximum": 20, "minimum": 1, "name": "count", "type": "integer", "x-example": 10}, {"description": "YouTube interface language, such as en, de, or pt-BR; defaults to en", "in": "query", "name": "hl", "type": "string", "x-example": "en"}, {"description": "Two-letter YouTube region code; defaults to US", "in": "query", "name": "gl", "type": "string", "x-example": "US"}], "path": "/youtube/suggest", "pathParams": [], "produces": ["application/json"], "queryParams": [{"in": "query", "name": "q", "required": true, "type": "string"}, {"in": "query", "name": "count", "type": "integer"}, {"in": "query", "name": "hl", "type": "string"}, {"in": "query", "name": "gl", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-tag": {"bodyParam": null, "bodyRequired": false, "id": "youtube-tag", "method": "GET", "params": [{"description": "Tag to filter videos", "in": "path", "name": "tag", "required": true, "type": "string", "x-example": "openai"}, {"default": "all", "description": "Result tab to load", "enum": ["all", "shorts"], "in": "query", "name": "type", "type": "string"}, {"description": "Continuation token for pagination, first page if empty", "in": "query", "name": "continuation_token", "type": "string"}], "path": "/youtube/tag/{tag}", "pathParams": ["tag"], "produces": ["application/json"], "queryParams": [{"enum": ["all", "shorts"], "in": "query", "name": "type", "type": "string"}, {"in": "query", "name": "continuation_token", "type": "string"}], "security": ["ApiKeyAuth"]}, "youtube-transcript": {"bodyParam": null, "bodyRequired": false, "id": "youtube-transcript", "method": "GET", "params": [{"description": "YouTube video ID (11-character code)", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "YbJOTdZBX1g"}, {"default": "en", "description": "Preferred transcript language", "in": "query", "name": "lang", "type": "string"}, {"description": "Translate transcript to this language code", "in": "query", "name": "translate_to", "type": "string"}, {"default": "json", "description": "Response format", "enum": ["json", "text", "srt", "vtt"], "in": "query", "name": "format", "type": "string"}, {"default": true, "description": "Include timestamps in the JSON response", "in": "query", "name": "timestamps", "type": "boolean"}], "path": "/youtube/transcript/{id}", "pathParams": ["id"], "produces": ["application/json", "text/plain"], "queryParams": [{"in": "query", "name": "lang", "type": "string"}, {"in": "query", "name": "translate_to", "type": "string"}, {"enum": ["json", "text", "srt", "vtt"], "in": "query", "name": "format", "type": "string"}, {"in": "query", "name": "timestamps", "type": "boolean"}], "security": ["ApiKeyAuth"]}, "youtube-transcript-languages": {"bodyParam": null, "bodyRequired": false, "id": "youtube-transcript-languages", "method": "GET", "params": [{"description": "YouTube video ID (11-character code)", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "YbJOTdZBX1g"}], "path": "/youtube/transcript/{id}/languages", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [], "security": ["ApiKeyAuth"]}, "youtube-video": {"bodyParam": null, "bodyRequired": false, "id": "youtube-video", "method": "GET", "params": [{"description": "YouTube video ID (11-char code)", "in": "path", "name": "id", "required": true, "type": "string", "x-example": "YbJOTdZBX1g"}], "path": "/youtube/video/{id}", "pathParams": ["id"], "produces": ["application/json"], "queryParams": [], "security": ["ApiKeyAuth"]}}
23
23
  JSON
24
24
  OPERATION_IDS = JSON.parse(<<~'JSON').freeze
25
- ["youtube-captions", "youtube-channel-playlists", "youtube-channel-search", "youtube-channel-shorts", "youtube-channel-videos", "youtube-comments", "youtube-playlist", "youtube-profile", "youtube-search", "youtube-suggest", "youtube-tag", "youtube-transcript", "youtube-transcript-languages", "youtube-video"]
25
+ ["youtube-captions", "youtube-channel-playlists", "youtube-channel-search", "youtube-channel-shorts", "youtube-channel-videos", "youtube-comment-replies", "youtube-comments", "youtube-playlist", "youtube-profile", "youtube-search", "youtube-suggest", "youtube-tag", "youtube-transcript", "youtube-transcript-languages", "youtube-video"]
26
26
  JSON
27
27
  OPERATION_COUNT = OPERATION_IDS.length
28
28
 
29
29
  class Client
30
30
  attr_reader :base_url
31
31
 
32
- def initialize(api_key: ENV["CRAWLORA_API_KEY"], base_url: "https://api.crawlora.net/api/v1", timeout: 30, user_agent: "crawlora-youtube-ruby/0.1.9", transport: nil)
32
+ def initialize(api_key: ENV["CRAWLORA_API_KEY"], base_url: "https://api.crawlora.net/api/v1", timeout: 30, user_agent: "crawlora-youtube-ruby/0.3.0", transport: nil)
33
33
  @api_key = api_key
34
34
  @base_url = base_url.to_s.sub(%r{/+$}, "")
35
35
  @timeout = Float(timeout)
@@ -138,6 +138,10 @@ module Crawlora
138
138
  response_type = params.delete(:response_type) || params.delete(:_response_type) || :auto
139
139
  request('youtube-comments', params, response_type: response_type)
140
140
  end
141
+ define_method('comment_replies') do |**params|
142
+ response_type = params.delete(:response_type) || params.delete(:_response_type) || :auto
143
+ request('youtube-comment-replies', params, response_type: response_type)
144
+ end
141
145
  define_method('playlist') do |**params|
142
146
  response_type = params.delete(:response_type) || params.delete(:_response_type) || :auto
143
147
  request('youtube-playlist', params, response_type: response_type)
@@ -1,5 +1,5 @@
1
1
  module Crawlora
2
2
  module Youtube
3
- VERSION = "0.1.9"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crawlora-youtube
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Crawlora
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-12 00:00:00.000000000 Z
11
+ date: 2026-11-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby client for Crawlora's hosted YouTube API. Covers search, channels,
14
- videos, playlists, comments, captions, and transcripts across 14 endpoints.
14
+ videos, playlists, comments, captions, and transcripts across 15 endpoints.
15
15
  email:
16
16
  executables: []
17
17
  extensions: []
@@ -48,5 +48,5 @@ requirements: []
48
48
  rubygems_version: 3.4.19
49
49
  signing_key:
50
50
  specification_version: 4
51
- summary: YouTube API client for Crawlora (14 endpoints)
51
+ summary: YouTube API client for Crawlora (15 endpoints)
52
52
  test_files: []