mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-18 17:16:26 +00:00
- Add ProgramSearchResultSerializer with nested channel/stream data - Implement ProgramSearchAPIView with comprehensive filtering: * Text search with AND/OR operators and parenthetical grouping * Regex pattern matching support * Whole word matching to avoid partial matches * Time-based filtering (airing_at, start/end ranges) * Channel/stream/group filtering * Configurable field selection for response customization * Pagination (50 default, 500 max per page) - Add /api/epg/programs/search/ endpoint - Add comprehensive API documentation - Enhanced Swagger/OpenAPI schema with examples Examples: - Complex queries: (Newcastle OR NEW) AND (Villa OR AST) - Whole words: title=NEW&title_whole_words=true - Regex: title=^Premier&title_regex=true - Time filtering: airing_at=2026-02-14T20:00:00Z
448 lines
11 KiB
Markdown
448 lines
11 KiB
Markdown
# EPG Program Search API
|
|
|
|
## Overview
|
|
|
|
The EPG Program Search API provides powerful filtering and search capabilities for EPG (Electronic Program Guide) program data. It supports complex text queries with AND/OR operators, parenthetical grouping, regex patterns, time-based filtering, and channel/stream matching.
|
|
|
|
**Endpoint:** `GET /api/epg/programs/search/`
|
|
|
|
**Authentication:** Required (JWT Bearer token)
|
|
|
|
---
|
|
|
|
## Query Parameters
|
|
|
|
### Text Search Parameters
|
|
|
|
#### **`title`** (string, optional)
|
|
Search program titles with support for:
|
|
- Simple terms: `title=football`
|
|
- AND operator: `title=premier AND league`
|
|
- OR operator: `title=Newcastle OR Villa`
|
|
- Nested groups with parentheses: `title=(Newcastle OR NEW) AND (Villa OR AST)`
|
|
- Default behavior: Space-separated terms use AND
|
|
|
|
**Examples:**
|
|
```
|
|
title=sports
|
|
title=premier AND league
|
|
title=Newcastle OR Villa
|
|
title=(Newcastle OR NEW) AND (Villa OR AST)
|
|
```
|
|
|
|
#### **`title_regex`** (boolean, optional)
|
|
When `true`, interprets the `title` parameter as a case-insensitive regex pattern.
|
|
|
|
**Examples:**
|
|
```
|
|
title=^The&title_regex=true # Programs starting with "The"
|
|
title=\d{4}&title_regex=true # Programs with 4-digit years
|
|
title=\b(United|City)\b&title_regex=true # Match "United" or "City" as whole words
|
|
```
|
|
|
|
#### **`title_whole_words`** (boolean, optional)
|
|
When `true`, matches only whole words. Prevents "NEW" from matching "News" or "Newcastle".
|
|
|
|
**Examples:**
|
|
```
|
|
title=NEW&title_whole_words=true # Matches "NEW" but not "News" or "Newsletter"
|
|
```
|
|
|
|
#### **`description`** (string, optional)
|
|
Search program descriptions. Supports the same features as `title`:
|
|
- AND/OR operators
|
|
- Parenthetical grouping
|
|
- Works with `description_regex` and `description_whole_words`
|
|
|
|
#### **`description_regex`** (boolean, optional)
|
|
When `true`, interprets `description` as a case-insensitive regex pattern.
|
|
|
|
#### **`description_whole_words`** (boolean, optional)
|
|
When `true`, matches only whole words in descriptions.
|
|
|
|
---
|
|
|
|
### Time Filtering Parameters
|
|
|
|
#### **`airing_at`** (ISO 8601 datetime, optional)
|
|
Find programs airing at a specific moment in time. Matches programs where:
|
|
```
|
|
start_time <= airing_at < end_time
|
|
```
|
|
|
|
**Example:**
|
|
```
|
|
airing_at=2026-02-14T20:00:00Z
|
|
```
|
|
|
|
#### **`start_after`** (ISO 8601 datetime, optional)
|
|
Programs starting at or after this time.
|
|
|
|
**Example:**
|
|
```
|
|
start_after=2026-02-14T18:00:00Z
|
|
```
|
|
|
|
#### **`start_before`** (ISO 8601 datetime, optional)
|
|
Programs starting at or before this time.
|
|
|
|
#### **`end_after`** (ISO 8601 datetime, optional)
|
|
Programs ending at or after this time.
|
|
|
|
#### **`end_before`** (ISO 8601 datetime, optional)
|
|
Programs ending at or before this time.
|
|
|
|
**Combined time range example:**
|
|
```
|
|
start_after=2026-02-14T19:00:00Z&start_before=2026-02-14T22:00:00Z
|
|
```
|
|
|
|
---
|
|
|
|
### Channel & Stream Filtering
|
|
|
|
#### **`channel`** (string, optional)
|
|
Filter by channel name (case-insensitive substring match).
|
|
|
|
**Example:**
|
|
```
|
|
channel=BBC One
|
|
```
|
|
|
|
#### **`channel_id`** (integer, optional)
|
|
Filter by exact channel ID.
|
|
|
|
**Example:**
|
|
```
|
|
channel_id=123
|
|
```
|
|
|
|
#### **`stream`** (string, optional)
|
|
Filter by stream name (case-insensitive substring match).
|
|
|
|
**Example:**
|
|
```
|
|
stream=Sky Sports
|
|
```
|
|
|
|
#### **`group`** (string, optional)
|
|
Filter by channel group name OR stream group name (case-insensitive substring match).
|
|
|
|
**Example:**
|
|
```
|
|
group=Sports
|
|
```
|
|
|
|
#### **`epg_source`** (integer, optional)
|
|
Filter by EPG source ID.
|
|
|
|
**Example:**
|
|
```
|
|
epg_source=5
|
|
```
|
|
|
|
---
|
|
|
|
### Response Customization
|
|
|
|
#### **`fields`** (string, optional)
|
|
Comma-separated list of fields to include in response. Reduces payload size for specific use cases.
|
|
|
|
**Available fields:**
|
|
- `id`, `title`, `sub_title`, `description`
|
|
- `start_time`, `end_time`, `tvg_id`, `custom_properties`
|
|
- `epg_source`, `epg_name`, `epg_icon_url`
|
|
- `channels`, `streams`
|
|
|
|
**Example:**
|
|
```
|
|
fields=title,start_time,end_time,channels
|
|
```
|
|
|
|
---
|
|
|
|
### Pagination Parameters
|
|
|
|
#### **`page`** (integer, optional, default: 1)
|
|
Page number for paginated results.
|
|
|
|
#### **`page_size`** (integer, optional, default: 50, max: 500)
|
|
Number of results per page.
|
|
|
|
**Example:**
|
|
```
|
|
page=2&page_size=100
|
|
```
|
|
|
|
---
|
|
|
|
## Response Format
|
|
|
|
### Standard Response (with pagination)
|
|
|
|
```json
|
|
{
|
|
"count": 345,
|
|
"next": "http://example.com/api/epg/programs/search/?page=2&...",
|
|
"previous": null,
|
|
"results": [
|
|
{
|
|
"id": 21382804,
|
|
"title": "Premier League: Newcastle vs Aston Villa",
|
|
"sub_title": "Match Week 25",
|
|
"description": "LIVE coverage from St James' Park",
|
|
"start_time": "2026-02-14T20:00:00Z",
|
|
"end_time": "2026-02-14T22:00:00Z",
|
|
"tvg_id": "skysportspremierleague.uk",
|
|
"custom_properties": {"category": "Sports"},
|
|
"epg_source": "Sky EPG UK",
|
|
"epg_name": "Sky Sports Premier League",
|
|
"epg_icon_url": "https://example.com/icon.png",
|
|
"channels": [
|
|
{
|
|
"id": 14419,
|
|
"name": "Sky Sports Premier League",
|
|
"channel_number": 401.0,
|
|
"channel_group": "UK | Sky Sports",
|
|
"tvg_id": "skysportspremierleague.uk"
|
|
}
|
|
],
|
|
"streams": [
|
|
{
|
|
"id": 300,
|
|
"name": "Sky Sports PL HD",
|
|
"channel_group": "UK | Sports",
|
|
"tvg_id": "SkySportsPL.uk",
|
|
"m3u_account": "my_provider"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### With Field Selection
|
|
|
|
Request: `?fields=title,start_time,end_time`
|
|
|
|
```json
|
|
{
|
|
"count": 345,
|
|
"next": "...",
|
|
"previous": null,
|
|
"results": [
|
|
{
|
|
"title": "Premier League: Newcastle vs Aston Villa",
|
|
"start_time": "2026-02-14T20:00:00Z",
|
|
"end_time": "2026-02-14T22:00:00Z"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Usage Examples
|
|
|
|
### Example 1: Find football matches airing now
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
"http://localhost:9191/api/epg/programs/search/?title=football&airing_at=2026-02-14T20:00:00Z"
|
|
```
|
|
|
|
### Example 2: Complex team search with abbreviations
|
|
Find programs mentioning either full names or abbreviations:
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
"http://localhost:9191/api/epg/programs/search/?title=(Newcastle%20OR%20NEW)%20AND%20(Villa%20OR%20AST)&airing_at=2026-02-14T20:00:00Z"
|
|
```
|
|
|
|
### Example 3: Whole word matching to avoid false positives
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
"http://localhost:9191/api/epg/programs/search/?title=NEW&title_whole_words=true&airing_at=2026-02-14T20:00:00Z"
|
|
```
|
|
This matches "NEW" but not "News", "Newcastle", or "Newsletter".
|
|
|
|
### Example 4: Regex pattern for advanced matching
|
|
Find programs starting with "Premier" or "Champions":
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
"http://localhost:9191/api/epg/programs/search/?title=^(Premier%7CChampions)&title_regex=true"
|
|
```
|
|
|
|
### Example 5: Time window search on specific channel
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
"http://localhost:9191/api/epg/programs/search/?channel=BBC%20One&start_after=2026-02-14T18:00:00Z&start_before=2026-02-14T23:00:00Z"
|
|
```
|
|
|
|
### Example 6: Minimal response with field selection
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
"http://localhost:9191/api/epg/programs/search/?title=sports&fields=title,start_time,end_time&page_size=10"
|
|
```
|
|
|
|
### Example 7: Find programs by stream group
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
"http://localhost:9191/api/epg/programs/search/?group=Sports&airing_at=2026-02-14T20:00:00Z"
|
|
```
|
|
|
|
### Example 8: Find all news programs in next 2 hours
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
"http://localhost:9191/api/epg/programs/search/?title=news&start_after=2026-02-14T20:00:00Z&start_before=2026-02-14T22:00:00Z"
|
|
```
|
|
|
|
---
|
|
|
|
## Text Query Syntax
|
|
|
|
### Operators
|
|
|
|
- **AND**: Both terms must be present
|
|
- Example: `premier AND league`
|
|
|
|
- **OR**: Either term must be present
|
|
- Example: `Newcastle OR Villa`
|
|
|
|
- **Parentheses**: Group operations for complex logic
|
|
- Example: `(A OR B) AND (C OR D)`
|
|
|
|
### Operator Precedence
|
|
|
|
Left-to-right evaluation with parentheses for grouping:
|
|
```
|
|
A AND B OR C → Evaluated as: (A AND B) OR C
|
|
(A OR B) AND C → A or B must match, AND C must match
|
|
A AND (B OR C) → A must match, AND either B or C must match
|
|
```
|
|
|
|
### Default Behavior
|
|
|
|
Space-separated terms without explicit operators default to AND:
|
|
```
|
|
football premier league → football AND premier AND league
|
|
```
|
|
|
|
---
|
|
|
|
## Performance Considerations
|
|
|
|
1. **Text searches** use database `LIKE` queries (or regex). For large datasets, consider:
|
|
- Using more specific search terms
|
|
- Combining with time filters to reduce result set
|
|
- Using field selection to reduce response size
|
|
|
|
2. **Pagination**: Default page size is 50, max is 500. For large result sets, use pagination rather than increasing page_size to max.
|
|
|
|
3. **Regex searches** are more expensive than standard text searches. Use only when necessary.
|
|
|
|
4. **Prefetching**: The endpoint automatically prefetches related channels, streams, and groups to avoid N+1 queries.
|
|
|
|
5. **Indexes**: The following fields are indexed for fast queries:
|
|
- `ProgramData.start_time`, `end_time`
|
|
- `EPGData.tvg_id`
|
|
- `Channel.channel_number`
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
### Authentication Required
|
|
```json
|
|
{
|
|
"detail": "Authentication credentials were not provided."
|
|
}
|
|
```
|
|
**Status:** 401 Unauthorized
|
|
|
|
### Invalid datetime format
|
|
Invalid ISO 8601 datetime values are silently ignored (filter not applied).
|
|
|
|
### Invalid regex pattern
|
|
If `title_regex=true` and pattern is invalid, the query may fail at the database level. Ensure regex patterns are valid.
|
|
|
|
---
|
|
|
|
## Integration Notes
|
|
|
|
### Frontend Integration
|
|
|
|
```javascript
|
|
// Example using fetch API
|
|
async function searchPrograms(query) {
|
|
const token = localStorage.getItem('accessToken');
|
|
const params = new URLSearchParams(query);
|
|
|
|
const response = await fetch(
|
|
`/api/epg/programs/search/?${params}`,
|
|
{
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
}
|
|
);
|
|
|
|
return await response.json();
|
|
}
|
|
|
|
// Usage
|
|
const results = await searchPrograms({
|
|
title: '(Newcastle OR NEW) AND (Villa OR AST)',
|
|
airing_at: new Date().toISOString(),
|
|
page_size: 20
|
|
});
|
|
```
|
|
|
|
### Automation & Scripts
|
|
|
|
```python
|
|
import requests
|
|
from datetime import datetime
|
|
|
|
# Get token
|
|
response = requests.post('http://localhost:9191/api/accounts/token/',
|
|
json={'username': 'user', 'password': 'pass'})
|
|
token = response.json()['access']
|
|
|
|
# Search programs
|
|
headers = {'Authorization': f'Bearer {token}'}
|
|
params = {
|
|
'title': 'football',
|
|
'airing_at': datetime.utcnow().isoformat() + 'Z',
|
|
'page_size': 50
|
|
}
|
|
|
|
response = requests.get(
|
|
'http://localhost:9191/api/epg/programs/search/',
|
|
headers=headers,
|
|
params=params
|
|
)
|
|
|
|
programs = response.json()
|
|
print(f"Found {programs['count']} matching programs")
|
|
```
|
|
|
|
---
|
|
|
|
## API Versioning
|
|
|
|
This endpoint was introduced in **version 1.0** and follows semantic versioning. Breaking changes will be announced with major version increments.
|
|
|
|
---
|
|
|
|
## Related Endpoints
|
|
|
|
- `GET /api/epg/grid/` - Get EPG grid view (24-hour window)
|
|
- `POST /api/epg/current-programs/` - Get currently airing programs for specific channels
|
|
- `GET /api/epg/programs/` - List all programs (CRUD endpoint)
|
|
- `GET /api/epg/sources/` - Manage EPG sources
|
|
|
|
---
|
|
|
|
## Support & Feedback
|
|
|
|
For issues, feature requests, or questions about this API, please file an issue on the GitHub repository or consult the project documentation.
|