Compare commits
3 Commits
80ac169126
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a87c1a2060 | |||
| 8ef206ebee | |||
| 0b955ed2b9 |
92
README.md
92
README.md
@@ -1,92 +0,0 @@
|
|||||||
# SVT Play Stream Launcher
|
|
||||||
|
|
||||||
A simple tool that lets you watch SVT Play programs directly in a video player.
|
|
||||||
|
|
||||||
## What It Does
|
|
||||||
|
|
||||||
This script makes it easy to search for and watch SVT Play programs. Instead of opening a web browser, you can:
|
|
||||||
|
|
||||||
1. Search for a program by name
|
|
||||||
2. Browse popular programs
|
|
||||||
3. Select what you want to watch
|
|
||||||
4. It opens in your video player automatically
|
|
||||||
|
|
||||||
## What You Need
|
|
||||||
|
|
||||||
Before using this script, make sure you have these programs installed:
|
|
||||||
|
|
||||||
- `yt-dlp` - Downloads video information
|
|
||||||
- `mpv` - Video player
|
|
||||||
- `zenity` - Creates the dialog windows
|
|
||||||
- `jq` - Processes data
|
|
||||||
- `curl` - Downloads information
|
|
||||||
|
|
||||||
The script will tell you if something is missing and how to install it.
|
|
||||||
|
|
||||||
## How to Use It
|
|
||||||
|
|
||||||
### Start the script
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./svt.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
A window will appear with two options:
|
|
||||||
- **Search for Program** - Type the name of what you want to watch
|
|
||||||
- **Browse Popular Programs** - See what's trending on SVT Play
|
|
||||||
|
|
||||||
### Example: Searching for a program
|
|
||||||
|
|
||||||
1. Click "Search for Program"
|
|
||||||
2. Type what you want (like "Wallander" or "News")
|
|
||||||
3. Wait 10-20 seconds for results (this is normal, the server is a bit slow)
|
|
||||||
4. Click on the program you want
|
|
||||||
5. It automatically opens in your video player
|
|
||||||
6. Enjoy!
|
|
||||||
|
|
||||||
### Example: Browsing popular programs
|
|
||||||
|
|
||||||
1. Click "Browse Popular Programs"
|
|
||||||
2. Wait for the list to load (10-20 seconds)
|
|
||||||
3. Scroll through and pick something
|
|
||||||
4. Press OK and it starts playing
|
|
||||||
|
|
||||||
## If Something Goes Wrong
|
|
||||||
|
|
||||||
### "Missing required tools"
|
|
||||||
You need to install something. The script will tell you exactly what to install. On Arch Linux:
|
|
||||||
```bash
|
|
||||||
sudo pacman -S yt-dlp mpv zenity jq curl
|
|
||||||
```
|
|
||||||
|
|
||||||
On Ubuntu/Debian:
|
|
||||||
```bash
|
|
||||||
sudo apt install yt-dlp mpv zenity jq curl
|
|
||||||
```
|
|
||||||
|
|
||||||
### "Program not found"
|
|
||||||
The program you searched for doesn't exist or isn't available on SVT Play right now.
|
|
||||||
|
|
||||||
### "Nothing happens after clicking OK"
|
|
||||||
This is usually just the server being slow. Wait a bit longer. The script is still working.
|
|
||||||
|
|
||||||
### "Video player doesn't open"
|
|
||||||
Make sure mpv is installed. Check with: `which mpv`
|
|
||||||
|
|
||||||
## See What's Happening
|
|
||||||
|
|
||||||
The script keeps a log of everything it's doing. If you want to see what's going on:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
tail -f ~/.svtplay.log
|
|
||||||
```
|
|
||||||
|
|
||||||
This shows you all the activity in real-time. Good for understanding what the script is doing.
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- Video plays in mpv, which is a lightweight video player
|
|
||||||
- Everything is logged to `~/.svtplay.log`
|
|
||||||
- The program searches the actual SVT Play website, not a saved list
|
|
||||||
- Searching and loading takes 10-20 seconds because the server is slow - this is normal
|
|
||||||
|
|
||||||
425
svt.sh
425
svt.sh
@@ -1,458 +1,113 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# SVT Play Stream Launcher - Search and stream SVT Play content with zenity
|
||||||
# SVT Play Stream Launcher - 100% GUI Based
|
|
||||||
# Search and stream SVT Play content with zenity interface
|
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Debug mode
|
|
||||||
DEBUG="${DEBUG:-0}"
|
|
||||||
WAIT_FOR_MPV=0
|
WAIT_FOR_MPV=0
|
||||||
|
|
||||||
# Logging
|
# Parse options
|
||||||
LOG_FILE="${HOME}/.svtplay.log"
|
|
||||||
mkdir -p "$(dirname "$LOG_FILE")"
|
|
||||||
|
|
||||||
# Parse command line options
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--debug) DEBUG=1; shift ;;
|
|
||||||
--wait) WAIT_FOR_MPV=1; shift ;;
|
--wait) WAIT_FOR_MPV=1; shift ;;
|
||||||
--log) tail -f "$LOG_FILE"; exit 0 ;;
|
|
||||||
--clear-log) rm -f "$LOG_FILE"; echo "Log cleared"; exit 0 ;;
|
|
||||||
--help|-h)
|
--help|-h)
|
||||||
zenity --info --title="SVT Play Launcher" --text="SVT Play Stream Launcher\n\nA GUI-based tool to search and stream SVT Play content.\n\nUsage: ./svt.sh [OPTIONS]\n\nOptions:\n --debug Enable debug output\n --wait Wait for playback to finish\n --log View live log\n --help Show this message"
|
zenity --info --title="SVT Play" --text="Usage: ./svt.sh [--wait|--help]"
|
||||||
exit 0
|
exit 0 ;;
|
||||||
;;
|
|
||||||
*) break ;;
|
*) break ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# Color definitions
|
# Force dark mode - works with GTK3 (GTK_THEME) and GTK4/libadwaita (ADW_DEBUG_COLOR_SCHEME)
|
||||||
readonly RED='\033[0;31m'
|
zenity_dark() { GTK_THEME=Adwaita:dark ADW_DEBUG_COLOR_SCHEME=prefer-dark zenity "$@"; }
|
||||||
readonly GREEN='\033[0;32m'
|
|
||||||
readonly YELLOW='\033[1;33m'
|
|
||||||
readonly BLUE='\033[0;34m'
|
|
||||||
readonly NC='\033[0m'
|
|
||||||
|
|
||||||
# Zenity dark mode helper
|
|
||||||
zenity_dark() {
|
|
||||||
GTK_THEME=Adwaita:dark zenity "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Logging functions
|
|
||||||
log_info() {
|
|
||||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $*"
|
|
||||||
echo -e "${BLUE}[INFO]${NC} $*" >&2
|
|
||||||
echo "$msg" >> "$LOG_FILE"
|
|
||||||
}
|
|
||||||
|
|
||||||
log_success() {
|
|
||||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [✓] $*"
|
|
||||||
echo -e "${GREEN}[✓]${NC} $*" >&2
|
|
||||||
echo "$msg" >> "$LOG_FILE"
|
|
||||||
}
|
|
||||||
|
|
||||||
log_error() {
|
|
||||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*"
|
|
||||||
echo -e "${RED}[ERROR]${NC} $*" >&2
|
|
||||||
echo "$msg" >> "$LOG_FILE"
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug() {
|
|
||||||
if [[ "$DEBUG" == "1" ]]; then
|
|
||||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [DEBUG] $*"
|
|
||||||
echo -e "${BLUE}[DEBUG]${NC} $*" >&2
|
|
||||||
echo "$msg" >> "$LOG_FILE"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check dependencies
|
|
||||||
check_dependencies() {
|
check_dependencies() {
|
||||||
log_info "Checking dependencies..."
|
|
||||||
|
|
||||||
local required=("yt-dlp" "mpv" "zenity" "jq" "curl")
|
|
||||||
local missing=()
|
local missing=()
|
||||||
|
for cmd in yt-dlp mpv zenity jq curl; do
|
||||||
for cmd in "${required[@]}"; do
|
command -v "$cmd" &>/dev/null || missing+=("$cmd")
|
||||||
if ! command -v "$cmd" &>/dev/null; then
|
|
||||||
missing+=("$cmd")
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ${#missing[@]} -gt 0 ]]; then
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||||
log_error "Missing required tools: ${missing[*]}"
|
zenity_dark --error --title="Missing Dependencies" --text="Please install: ${missing[*]}"
|
||||||
zenity_dark --error --title="Missing Dependencies" --text="Please install: ${missing[*]}\n\nArch: sudo pacman -S ${missing[*]}\nDebian: sudo apt install ${missing[*]}"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log_success "Dependencies OK"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Search programs via SVT Play GraphQL API
|
|
||||||
search_programs() {
|
search_programs() {
|
||||||
local query="$1"
|
local query="$1"
|
||||||
log_info "API: Querying searchPage with: $query"
|
local response http_code
|
||||||
|
response=$(curl -s --connect-timeout 10 --max-time 30 -w "\n%{http_code}" -X POST \
|
||||||
|
"https://api.svt.se/contento/graphql" -H "Content-Type: application/json" \
|
||||||
|
-d "{\"query\": \"{ searchPage(query: \\\"${query}\\\", maxHits: 50) { flat { hits { teaser { heading item { urls { svtplay } } } } } } }\"}" 2>/dev/null) || return 1
|
||||||
|
|
||||||
# Make API call with searchPage (with longer timeout since SVT API can be slow)
|
http_code=$(echo "$response" | tail -1)
|
||||||
local response
|
|
||||||
response=$(curl -s --connect-timeout 10 --max-time 30 -w "\n%{http_code}" -X POST "https://api.svt.se/contento/graphql" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "{\"query\": \"{ searchPage(query: \\\"${query}\\\", maxHits: 50) { flat { hits { teaser { heading } } } } }\"}" 2>/dev/null) || {
|
|
||||||
log_error "Failed to query SVT Play API (curl error)"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
local http_code=$(echo "$response" | tail -1)
|
|
||||||
response=$(echo "$response" | sed '$d')
|
response=$(echo "$response" | sed '$d')
|
||||||
|
|
||||||
log_info "API: Response HTTP $http_code"
|
[[ "$http_code" != "200" ]] && return 1
|
||||||
|
|
||||||
if [[ "$http_code" != "200" ]]; then
|
|
||||||
log_error "API returned HTTP $http_code"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check for GraphQL errors
|
|
||||||
if echo "$response" | jq -e '.errors' >/dev/null 2>&1; then
|
|
||||||
log_error "GraphQL error: $(echo "$response" | jq -r '.errors[0].message // "Unknown error"')"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Parse response - extract headings, clean HTML, and convert to slugs
|
|
||||||
local results
|
local results
|
||||||
results=$(echo "$response" | jq -r '.data.searchPage.flat.hits[].teaser | select(.heading != null) | .heading as $title | ($title | ascii_downcase | gsub("<[^>]*>"; "") | gsub("[^a-z0-9 ]"; ""; "g") | gsub("^ +| +$"; "") | gsub(" +"; "-")) as $slug | $title + "|" + $slug' 2>/dev/null)
|
results=$(echo "$response" | jq -r '
|
||||||
local jq_ret=$?
|
.data.searchPage.flat.hits[].teaser |
|
||||||
|
select(.heading != null and .item.urls.svtplay != null) |
|
||||||
if [[ $jq_ret -ne 0 ]]; then
|
(.heading | gsub("<[^>]*>"; "")) + "|" + (.item.urls.svtplay | ltrimstr("/"))
|
||||||
log_error "jq parsing failed (ret=$jq_ret)"
|
' 2>/dev/null)
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$results" ]]; then
|
|
||||||
log_warn "No results from search"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
local result_count=$(echo "$results" | grep -c '|')
|
|
||||||
log_info "API: Search returned $result_count results"
|
|
||||||
|
|
||||||
|
[[ -z "$results" ]] && return 1
|
||||||
echo "$results"
|
echo "$results"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get all active programs from Tablåtjänsten
|
|
||||||
get_popular_programs() {
|
|
||||||
log_info "API: Fetching popular programs"
|
|
||||||
|
|
||||||
# Use GraphQL API with broad search query "a" to get popular/varied content (with longer timeout)
|
|
||||||
local response
|
|
||||||
response=$(curl -s --connect-timeout 10 --max-time 30 -w "\n%{http_code}" -X POST "https://api.svt.se/contento/graphql" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"query": "{ searchPage(query: \"a\", maxHits: 50) { flat { hits { teaser { heading } } } } }"}' 2>/dev/null) || {
|
|
||||||
log_error "API: Failed to query (curl error)"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
local http_code=$(echo "$response" | tail -1)
|
|
||||||
response=$(echo "$response" | sed '$d')
|
|
||||||
|
|
||||||
log_info "API: Popular programs response HTTP $http_code"
|
|
||||||
|
|
||||||
if [[ "$http_code" != "200" ]]; then
|
|
||||||
log_error "API returned HTTP $http_code for popular programs"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check response is not empty
|
|
||||||
local resp_len=$(echo "$response" | wc -c)
|
|
||||||
log_info "API: Response size: $resp_len bytes"
|
|
||||||
|
|
||||||
if [[ $resp_len -lt 50 ]]; then
|
|
||||||
log_error "API: Response too small, likely error: $response"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Parse flat hits (popular programs)
|
|
||||||
# Format output: title|slug
|
|
||||||
local results
|
|
||||||
log_info "API: Parsing results with jq"
|
|
||||||
results=$(echo "$response" | jq -r '.data.searchPage.flat.hits[].teaser | select(.heading != null) | .heading as $title | ($title | ascii_downcase | gsub("<[^>]*>"; "") | gsub("[^a-z0-9 ]"; ""; "g") | gsub("^ +| +$"; "") | gsub(" +"; "-")) as $slug | $title + "|" + $slug' 2>/dev/null)
|
|
||||||
local jq_ret=$?
|
|
||||||
|
|
||||||
if [[ $jq_ret -ne 0 ]]; then
|
|
||||||
log_error "jq parsing failed (ret=$jq_ret), response: $response"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$results" ]]; then
|
|
||||||
log_warn "API: jq returned empty results"
|
|
||||||
log_info "API: Full response: $response"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
local result_count=$(echo "$results" | grep -c '|')
|
|
||||||
log_info "API: Popular programs parsed $result_count results"
|
|
||||||
|
|
||||||
echo "$results"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Show search dialog
|
|
||||||
show_search_dialog() {
|
show_search_dialog() {
|
||||||
log_info "Showing search dialog"
|
zenity_dark --entry --title="Search SVT Play" --text="Program name:" --width=400 2>/dev/null
|
||||||
|
|
||||||
local search_term
|
|
||||||
search_term=$(zenity_dark --entry \
|
|
||||||
--title="Search SVT Play" \
|
|
||||||
--text="Enter program name to search:" \
|
|
||||||
--width=500 \
|
|
||||||
2>/dev/null)
|
|
||||||
|
|
||||||
if [[ -z "$search_term" ]]; then
|
|
||||||
log_debug "Search cancelled"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_debug "Search term: $search_term"
|
|
||||||
echo "$search_term"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Show results in zenity list
|
|
||||||
show_results_list() {
|
show_results_list() {
|
||||||
local results="$1"
|
local results="$1" temp_file="/tmp/svt_$$"
|
||||||
log_debug "Showing results list"
|
|
||||||
|
|
||||||
if [[ -z "$results" ]]; then
|
# Build zenity list and mapping file
|
||||||
log_warn "No results provided"
|
|
||||||
zenity_dark --error --title="No Results" --text="No programs found."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
local result_count=$(echo "$results" | wc -l)
|
|
||||||
log_debug "Found $result_count results"
|
|
||||||
|
|
||||||
# Create temp file with formatted list for zenity
|
|
||||||
local temp_file="/tmp/svt_search_$$.txt"
|
|
||||||
local idx=0
|
local idx=0
|
||||||
|
|
||||||
while IFS='|' read -r title slug; do
|
while IFS='|' read -r title slug; do
|
||||||
[[ -z "$title" || -z "$slug" ]] && continue
|
[[ -z "$title" || -z "$slug" ]] && continue
|
||||||
((idx++))
|
((idx++))
|
||||||
|
title=$(echo "$title" | sed 's/&/\&/g; s/"/"/g; s/</</g; s/>/>/g')
|
||||||
# Clean HTML tags
|
|
||||||
title=$(echo "$title" | sed 's/<[^>]*>//g' | sed 's/&/\&/g' | sed 's/"/"/g' | sed "s/'/'/g" | sed 's/</</g' | sed 's/>/>/g')
|
|
||||||
|
|
||||||
# Save title->slug mapping
|
|
||||||
echo "$title=$slug" >> "$temp_file.map"
|
echo "$title=$slug" >> "$temp_file.map"
|
||||||
|
[[ $idx -eq 1 ]] && echo "TRUE" >> "$temp_file" || echo "FALSE" >> "$temp_file"
|
||||||
if [[ $idx -eq 1 ]]; then
|
|
||||||
echo "TRUE" >> "$temp_file"
|
|
||||||
else
|
|
||||||
echo "FALSE" >> "$temp_file"
|
|
||||||
fi
|
|
||||||
echo "$title" >> "$temp_file"
|
echo "$title" >> "$temp_file"
|
||||||
done <<< "$results"
|
done <<< "$results"
|
||||||
|
|
||||||
[[ $idx -eq 0 ]] && { rm -f "$temp_file"*; return 1; }
|
[[ $idx -eq 0 ]] && { rm -f "$temp_file"*; return 1; }
|
||||||
|
|
||||||
log_debug "Built list with $idx items"
|
|
||||||
|
|
||||||
# Display zenity dialog
|
|
||||||
local selected
|
local selected
|
||||||
selected=$(zenity_dark --list --title="Search Results" --text="Select a program:" --column="Select" --column="Program" --radiolist --width=700 --height=500 < "$temp_file" 2>/dev/null)
|
selected=$(zenity_dark --list --title="Results" --text="Select program:" \
|
||||||
|
--column="Select" --column="Program" --radiolist --width=700 --height=500 < "$temp_file" 2>/dev/null)
|
||||||
if [[ -z "$selected" ]]; then
|
|
||||||
log_debug "User cancelled"
|
|
||||||
rm -f "$temp_file"*
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Look up slug
|
|
||||||
local slug
|
|
||||||
slug=$(grep "^$selected=" "$temp_file.map" 2>/dev/null | cut -d= -f2)
|
|
||||||
|
|
||||||
|
local slug=""
|
||||||
|
[[ -n "$selected" ]] && slug=$(grep "^${selected}=" "$temp_file.map" 2>/dev/null | cut -d= -f2)
|
||||||
rm -f "$temp_file"*
|
rm -f "$temp_file"*
|
||||||
|
|
||||||
if [[ -z "$slug" ]]; then
|
[[ -z "$slug" ]] && return 1
|
||||||
log_error "Could not map selection to slug"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_success "Selected: $selected"
|
|
||||||
echo "$slug"
|
echo "$slug"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Show popular programs
|
|
||||||
show_popular_programs() {
|
|
||||||
log_info "Fetching popular programs from SVT Play..."
|
|
||||||
|
|
||||||
# Get programs (API call takes 10-20 seconds)
|
|
||||||
local programs
|
|
||||||
programs=$(get_popular_programs)
|
|
||||||
|
|
||||||
if [[ -z "$programs" ]]; then
|
|
||||||
log_error "No popular programs fetched"
|
|
||||||
zenity_dark --error --title="Error" --text="Failed to fetch popular programs from SVT Play."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_info "Got $(echo "$programs" | wc -l) results, preparing list..."
|
|
||||||
|
|
||||||
# Create temp file with formatted list for zenity
|
|
||||||
local temp_file="/tmp/svt_list_$$.txt"
|
|
||||||
local idx=0
|
|
||||||
local first_title=""
|
|
||||||
|
|
||||||
while IFS='|' read -r title slug; do
|
|
||||||
[[ -z "$title" || -z "$slug" ]] && continue
|
|
||||||
((idx++))
|
|
||||||
|
|
||||||
# Clean HTML tags
|
|
||||||
title=$(echo "$title" | sed 's/<[^>]*>//g' | sed 's/&/\&/g' | sed 's/"/"/g' | sed "s/'/'/g" | sed 's/</</g' | sed 's/>/>/g')
|
|
||||||
|
|
||||||
# Save title->slug mapping
|
|
||||||
echo "$title=$slug" >> "$temp_file.map"
|
|
||||||
|
|
||||||
if [[ $idx -eq 1 ]]; then
|
|
||||||
echo "TRUE" >> "$temp_file"
|
|
||||||
first_title="$title"
|
|
||||||
else
|
|
||||||
echo "FALSE" >> "$temp_file"
|
|
||||||
fi
|
|
||||||
echo "$title" >> "$temp_file"
|
|
||||||
done <<< "$programs"
|
|
||||||
|
|
||||||
[[ $idx -eq 0 ]] && { log_error "No valid items"; rm -f "$temp_file"*; return 1; }
|
|
||||||
|
|
||||||
log_info "Built list with $idx items"
|
|
||||||
|
|
||||||
# Display zenity dialog with the list
|
|
||||||
log_info "Showing zenity list dialog..."
|
|
||||||
local selected
|
|
||||||
selected=$(zenity_dark --list --title="Popular Programs" --text="Select a program to stream:" --column="Select" --column="Program" --radiolist --width=700 --height=600 < "$temp_file" 2>/dev/null)
|
|
||||||
|
|
||||||
local ret=$?
|
|
||||||
|
|
||||||
if [[ $ret -ne 0 ]] || [[ -z "$selected" ]]; then
|
|
||||||
log_debug "User cancelled or dialog failed (ret=$ret)"
|
|
||||||
rm -f "$temp_file"*
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Look up slug from the selected title
|
|
||||||
local slug
|
|
||||||
slug=$(grep "^$selected=" "$temp_file.map" 2>/dev/null | cut -d= -f2)
|
|
||||||
|
|
||||||
rm -f "$temp_file"*
|
|
||||||
|
|
||||||
if [[ -z "$slug" ]]; then
|
|
||||||
log_error "Could not find slug for: $selected"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_success "Selected: $selected"
|
|
||||||
echo "$slug"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Show main menu
|
|
||||||
show_main_menu() {
|
|
||||||
log_info "Showing main menu"
|
|
||||||
|
|
||||||
local choice
|
|
||||||
choice=$(zenity_dark --list \
|
|
||||||
--title="SVT Play Stream Launcher" \
|
|
||||||
--text="Select an option:" \
|
|
||||||
--column="Option" \
|
|
||||||
"Search for Program" \
|
|
||||||
"Browse Popular Programs" \
|
|
||||||
--width=400 \
|
|
||||||
--height=200 \
|
|
||||||
2>/dev/null)
|
|
||||||
|
|
||||||
if [[ -z "$choice" ]]; then
|
|
||||||
log_debug "User cancelled main menu"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$choice"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Play program directly
|
|
||||||
play_program() {
|
play_program() {
|
||||||
local slug="$1"
|
local url="https://www.svtplay.se/$1"
|
||||||
local url="https://www.svtplay.se/$slug"
|
|
||||||
|
|
||||||
log_info "Playing program: $slug"
|
|
||||||
log_debug "URL: $url"
|
|
||||||
|
|
||||||
# Verify URL is accessible
|
|
||||||
if ! yt-dlp --quiet --dump-json "$url" &>/dev/null; then
|
|
||||||
log_error "Failed to access program: $slug"
|
|
||||||
zenity_dark --error --title="Error" --text="Failed to access program. It may not be available."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_success "Starting playback for: $slug"
|
|
||||||
|
|
||||||
# Launch mpv with yt-dlp integration
|
|
||||||
mpv --force-window=immediate "$url" &
|
mpv --force-window=immediate "$url" &
|
||||||
local pid=$!
|
[[ "$WAIT_FOR_MPV" == "1" ]] && wait $! 2>/dev/null
|
||||||
|
|
||||||
log_success "Playback started (PID: $pid)"
|
|
||||||
|
|
||||||
if [[ "$WAIT_FOR_MPV" == "1" ]]; then
|
|
||||||
log_info "Waiting for mpv to finish..."
|
|
||||||
wait $pid 2>/dev/null
|
|
||||||
log_success "Playback finished"
|
|
||||||
else
|
|
||||||
log_info "Playback continues in background"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main function
|
|
||||||
main() {
|
main() {
|
||||||
log_info "═════ SVT Play Stream Launcher started ═════"
|
|
||||||
log_info "PID: $$, DIR: $PWD"
|
|
||||||
|
|
||||||
check_dependencies
|
check_dependencies
|
||||||
|
|
||||||
# Show main menu
|
|
||||||
local menu_choice
|
|
||||||
menu_choice=$(show_main_menu) || exit 0
|
|
||||||
|
|
||||||
local program_slug
|
|
||||||
|
|
||||||
case "$menu_choice" in
|
|
||||||
"Search for Program")
|
|
||||||
local search_term
|
local search_term
|
||||||
search_term=$(show_search_dialog) || exit 0
|
search_term=$(show_search_dialog) || exit 0
|
||||||
|
[[ -z "$search_term" ]] && exit 0
|
||||||
|
|
||||||
log_info "Searching for: $search_term"
|
local results
|
||||||
|
results=$(search_programs "$search_term") || {
|
||||||
# Get search results (API call takes 10-20 seconds)
|
|
||||||
search_results=$(search_programs "$search_term")
|
|
||||||
|
|
||||||
if [[ -z "$search_results" ]]; then
|
|
||||||
zenity_dark --error --title="No Results" --text="No programs found for: $search_term"
|
zenity_dark --error --title="No Results" --text="No programs found for: $search_term"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
}
|
||||||
|
|
||||||
program_slug=$(show_results_list "$search_results") || exit 0
|
local slug
|
||||||
;;
|
slug=$(show_results_list "$results") || exit 0
|
||||||
"Browse Popular Programs")
|
|
||||||
program_slug=$(show_popular_programs) || exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
log_error "Invalid menu choice: $menu_choice"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Play the selected program
|
play_program "$slug"
|
||||||
play_program "$program_slug"
|
|
||||||
|
|
||||||
log_success "Session complete"
|
|
||||||
log_info "═════════════════════════════════════════════════════"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Only run main if script is executed directly (not sourced)
|
|
||||||
[[ "${BASH_SOURCE[0]}" == "${0}" ]] && main "$@"
|
[[ "${BASH_SOURCE[0]}" == "${0}" ]] && main "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user