Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d8ab57e20 | |||
| d33a022676 | |||
| 7e2ef1fa2b | |||
| 164cad456c | |||
| 0b091a1afd | |||
| cfc7ad39f2 | |||
| 8a64a269f3 | |||
| 908255e5cf | |||
| 39297d4aa5 | |||
| d39cb3f3d4 | |||
| c70f83d04a | |||
| 3329cf9ac2 | |||
| 6d4e490283 | |||
| d3490e1521 | |||
| 0c2201fab5 | |||
| f7b75fa72f | |||
| 2c7fcdb5ae | |||
| 0bdac16250 | |||
| 6eeab58464 | |||
| 08a35bddeb | |||
| bbcf767a8f | |||
| b1bd4ed365 | |||
| 2b3551cada | |||
| d611f60743 | |||
| d85a8d4511 | |||
| f0271e61df | |||
| 3164a70e48 | |||
| 8d3d67a177 | |||
| f9985fc693 |
@@ -0,0 +1,48 @@
|
|||||||
|
# API Keys
|
||||||
|
OPENROUTER_API_KEY=
|
||||||
|
ELEVENLABS_API_KEY=
|
||||||
|
INWORLD_API_KEY=
|
||||||
|
OPENAI_API_KEY=
|
||||||
|
|
||||||
|
# SignalWire (real callers)
|
||||||
|
SIGNALWIRE_PROJECT_ID=
|
||||||
|
SIGNALWIRE_SPACE=
|
||||||
|
SIGNALWIRE_TOKEN=
|
||||||
|
SIGNALWIRE_PHONE=
|
||||||
|
SIGNALWIRE_STREAM_URL=
|
||||||
|
|
||||||
|
# Social media
|
||||||
|
TWITTER_API_KEY=
|
||||||
|
TWITTER_API_SECRET=
|
||||||
|
TWITTER_ACCESS_TOKEN=
|
||||||
|
TWITTER_ACCESS_TOKEN_SECRET=
|
||||||
|
CLIENT_SECRET_ID=
|
||||||
|
CLIENT_SECRET=
|
||||||
|
POSTIZ_URL=
|
||||||
|
POSTIZ_API_KEY=
|
||||||
|
BSKY_APP_PASSWORD=
|
||||||
|
|
||||||
|
# Castopod
|
||||||
|
CASTOPOD_USERNAME=admin
|
||||||
|
CASTOPOD_PASSWORD=
|
||||||
|
CASTOPOD_DB_PASS=
|
||||||
|
|
||||||
|
# Postiz publishing
|
||||||
|
POSTIZ_JWT_SECRET=
|
||||||
|
POSTIZ_USER_ID=
|
||||||
|
POSTIZ_INTEGRATIONS={}
|
||||||
|
|
||||||
|
# BunnyCDN
|
||||||
|
BUNNY_STORAGE_KEY=
|
||||||
|
BUNNY_ACCOUNT_KEY=
|
||||||
|
|
||||||
|
# Monitoring
|
||||||
|
HEARTBEAT_URL=
|
||||||
|
|
||||||
|
# Google AI
|
||||||
|
GOOGLE_API_KEY=
|
||||||
|
|
||||||
|
# Email (IMAP)
|
||||||
|
SUBMISSIONS_IMAP_HOST=
|
||||||
|
SUBMISSIONS_IMAP_USER=
|
||||||
|
SUBMISSIONS_IMAP_PASS=
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
2c7fcdb5aecbb0d3bf039abab9e723d62bc8fe1a
|
||||||
@@ -50,5 +50,12 @@ voices-v1.0.bin
|
|||||||
# Reference voices for TTS
|
# Reference voices for TTS
|
||||||
ref_audio/
|
ref_audio/
|
||||||
|
|
||||||
|
# YouTube OAuth credentials
|
||||||
|
youtube_client_secrets.json
|
||||||
|
youtube_token.json
|
||||||
|
|
||||||
|
# Clip upload history (local)
|
||||||
|
upload-history.json
|
||||||
|
|
||||||
# Claude settings (local)
|
# Claude settings (local)
|
||||||
.claude/
|
.claude/
|
||||||
|
|||||||
@@ -18,15 +18,14 @@
|
|||||||
## Castopod (Podcast Publishing)
|
## Castopod (Podcast Publishing)
|
||||||
- **URL**: https://podcast.macneilmediagroup.com
|
- **URL**: https://podcast.macneilmediagroup.com
|
||||||
- **Podcast handle**: `@LukeAtTheRoost`
|
- **Podcast handle**: `@LukeAtTheRoost`
|
||||||
- **API Auth**: Basic auth (admin/podcast2026api)
|
- **API Auth**: Basic auth (credentials in .env: CASTOPOD_USERNAME, CASTOPOD_PASSWORD)
|
||||||
- **Container**: `castopod-castopod-1`
|
- **Container**: `castopod-castopod-1`
|
||||||
- **Database**: `castopod-mariadb-1` (user: castopod, db: castopod)
|
- **Database**: `castopod-mariadb-1` (user: castopod, db: castopod)
|
||||||
|
|
||||||
## Running the App
|
## Running the App
|
||||||
```bash
|
```bash
|
||||||
# Start backend
|
# Start backend — ALWAYS use --reload-dir to avoid CPU thrashing from file watchers
|
||||||
cd /Users/lukemacneil/ai-podcast
|
python -m uvicorn backend.main:app --reload --reload-dir backend --host 0.0.0.0 --port 8000
|
||||||
python -m uvicorn backend.main:app --reload --host 0.0.0.0 --port 8000
|
|
||||||
|
|
||||||
# Or use run.sh
|
# Or use run.sh
|
||||||
./run.sh
|
./run.sh
|
||||||
@@ -56,10 +55,57 @@ Required in `.env`:
|
|||||||
- `_pick_response_budget()` in main.py controls caller dialog token limits (150-450 tokens). MiniMax respects limits strictly — if responses seem short, check these values.
|
- `_pick_response_budget()` in main.py controls caller dialog token limits (150-450 tokens). MiniMax respects limits strictly — if responses seem short, check these values.
|
||||||
- Default max_tokens in llm.py is 300 (for non-caller uses)
|
- Default max_tokens in llm.py is 300 (for non-caller uses)
|
||||||
- Grok (`x-ai/grok-4-fast`) works well for natural dialog; MiniMax tends toward terse responses
|
- Grok (`x-ai/grok-4-fast`) works well for natural dialog; MiniMax tends toward terse responses
|
||||||
|
- `generate_with_tools()` in llm.py supports OpenRouter function calling for the intern feature
|
||||||
|
|
||||||
|
## Caller Generation System
|
||||||
|
- **CallerBackground dataclass**: Structured output from LLM background generation (JSON mode). Fields: name, age, gender, job, location, reason_for_calling, pool_name, communication_style, energy_level, emotional_state, signature_detail, situation_summary, natural_description, seeds, verbal_fluency, calling_from.
|
||||||
|
- **Voice-personality matching**: `_match_voices_to_styles()` runs after background generation. 68 voice profiles in `VOICE_PROFILES` (tts.py), 18 style-to-voice mappings in `STYLE_VOICE_PREFERENCES` (main.py). Soft matching — scores voices against style preferences.
|
||||||
|
- **Adaptive call shapes**: `SHAPE_STYLE_AFFINITIES` maps communication styles to shape weight multipliers. Consecutive shape repeats are dampened.
|
||||||
|
- **Inter-caller awareness**: Thematic matching in `get_show_history()` scores previous callers by keyword/category overlap. Adaptive reaction frequency (60%/35%/15%). Show energy tracking via `_get_show_energy()`.
|
||||||
|
- **Caller memory**: Returning callers store structured backgrounds, key moments, arc status, and relationships with other regulars. `RegularCallerService` has `add_relationship()` and expanded `update_after_call()`.
|
||||||
|
- **Show pacing**: `_sort_caller_queue()` sorts presentation order by energy alternation, topic variety, shape variety.
|
||||||
|
- **Call quality signals**: `_assess_call_quality()` captures exchange count, response length, host engagement, shape target hit, natural ending.
|
||||||
|
|
||||||
|
## Devon (Intern Character)
|
||||||
|
- **Service**: `backend/services/intern.py` — persistent show character, not a caller
|
||||||
|
- **Personality**: 23-year-old NMSU grad, eager, slightly incompetent, gets yelled at. Voice: "Nate" (Inworld), no phone filter.
|
||||||
|
- **Tools**: web_search (SearXNG), get_headlines, fetch_webpage, wikipedia_lookup — via `generate_with_tools()` function calling
|
||||||
|
- **Endpoints**: `POST /api/intern/ask`, `/interject`, `/monitor`, `GET /api/intern/suggestion`, `POST /api/intern/suggestion/play`, `/dismiss`
|
||||||
|
- **Auto-monitoring**: Watches conversation every 15s during calls, buffers suggestions for host approval
|
||||||
|
- **Persistence**: `data/intern.json` stores lookup history
|
||||||
|
- **Frontend**: Ask Devon input (D key), Interject button, monitor toggle, suggestion indicator with Play/Dismiss
|
||||||
|
|
||||||
|
## Frontend Control Panel
|
||||||
|
- **Keyboard shortcuts**: 1-0 (callers), H (hangup), W (wrap up), M (music toggle), D (ask Devon), Escape (close modals)
|
||||||
|
- **Wrap It Up**: Amber button that signals callers to wind down gracefully. Reduces response budget, injects wrap-up signals, forces goodbye after 2 exchanges.
|
||||||
|
- **Caller info panel**: Shows call shape, energy level, emotional state, signature detail, situation summary during active calls
|
||||||
|
- **Caller buttons**: Energy dots (colored by level) and shape badges on each button
|
||||||
|
- **Pinned SFX**: Cheer/Applause/Boo always visible, rest collapsible
|
||||||
|
- **Visual polish**: Thinking pulse, call glow, compact media row, smoother transitions
|
||||||
|
|
||||||
## Website
|
## Website
|
||||||
- **Domain**: lukeattheroost.com (behind Cloudflare)
|
- **Domain**: lukeattheroost.com (behind Cloudflare)
|
||||||
- **Analytics**: Cloudflare Web Analytics (enable in Cloudflare dashboard, no code changes needed)
|
- **Analytics**: Cloudflare Web Analytics (enable in Cloudflare dashboard, no code changes needed)
|
||||||
|
- **Deploy**: `npx wrangler pages deploy website/ --project-name=lukeattheroost --branch=main`
|
||||||
|
|
||||||
|
## Git Push
|
||||||
|
- If `mmgnas` times out, use the 10g hostname:
|
||||||
|
```bash
|
||||||
|
GIT_SSH_COMMAND="ssh -o HostName=mmgnas-10g -p 2222 -i ~/.ssh/gitea_mmgnas" git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hetzner VPS
|
||||||
|
- **IP**: `46.225.164.41`
|
||||||
|
- **SSH**: `ssh root@46.225.164.41` (uses default key `~/.ssh/id_rsa`)
|
||||||
|
- **Specs**: 2 CPU, 4GB RAM, 38GB disk (~33GB free)
|
||||||
|
- **Mail**: `docker-mailserver` at `/opt/mailserver/`
|
||||||
|
- **Manage accounts**: `docker exec mailserver setup email add/del/list`
|
||||||
|
- **Available for future services** — has headroom for lightweight containers. Not suitable for storage-heavy services (e.g. Castopod with daily episodes) without a disk upgrade or attached volume.
|
||||||
|
|
||||||
|
## Podcast Workflow
|
||||||
|
- Publishing pipeline: episodes go through Castopod, CDN, website, YouTube, and social
|
||||||
|
- Always check Python venv is active and packages are installed before running publish scripts
|
||||||
|
- Episode numbering must be verified against existing episodes
|
||||||
|
|
||||||
## Episodes Published
|
## Episodes Published
|
||||||
- Episode 6 published 2026-02-08 (podcast6.mp3, ~31 min)
|
- Episode 6 published 2026-02-08 (podcast6.mp3, ~31 min)
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Luke MacNeil / MacNeil Media Group, LLC
|
||||||
|
https://macneilmediagroup.com
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Analyze silence gaps in podcast stems to find optimal strip-silence thresholds.
|
||||||
|
|
||||||
|
Usage: python analyze_gaps.py recordings/2026-03-17_235137/
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
import numpy as np
|
||||||
|
import soundfile as sf
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BLOCK_SEC = 0.1
|
||||||
|
SILENCE_DB = -30
|
||||||
|
THRESHOLD = 10 ** (SILENCE_DB / 20)
|
||||||
|
MIN_VOICE_SEC = 0.3
|
||||||
|
|
||||||
|
|
||||||
|
def load_stem(path: Path) -> tuple[np.ndarray, int]:
|
||||||
|
audio, sr = sf.read(path, dtype="float32")
|
||||||
|
if audio.ndim > 1:
|
||||||
|
audio = audio[:, 0]
|
||||||
|
return audio, sr
|
||||||
|
|
||||||
|
|
||||||
|
def compute_rms_blocks(audio: np.ndarray, sr: int) -> np.ndarray:
|
||||||
|
block_samples = int(sr * BLOCK_SEC)
|
||||||
|
n_blocks = len(audio) // block_samples
|
||||||
|
if n_blocks == 0:
|
||||||
|
return np.array([0.0])
|
||||||
|
trimmed = audio[:n_blocks * block_samples].reshape(n_blocks, block_samples)
|
||||||
|
return np.sqrt(np.mean(trimmed ** 2, axis=1))
|
||||||
|
|
||||||
|
|
||||||
|
def compute_peak_blocks(audio: np.ndarray, sr: int) -> np.ndarray:
|
||||||
|
block_samples = int(sr * BLOCK_SEC)
|
||||||
|
n_blocks = len(audio) // block_samples
|
||||||
|
if n_blocks == 0:
|
||||||
|
return np.array([0.0])
|
||||||
|
trimmed = audio[:n_blocks * block_samples].reshape(n_blocks, block_samples)
|
||||||
|
return np.max(np.abs(trimmed), axis=1)
|
||||||
|
|
||||||
|
|
||||||
|
def analyze(stems_dir: Path):
|
||||||
|
stems_dir = Path(stems_dir)
|
||||||
|
voice_stems = {}
|
||||||
|
for name in ["host", "devon", "caller"]:
|
||||||
|
path = stems_dir / f"{name}.wav"
|
||||||
|
if path.exists():
|
||||||
|
print(f"Loading {name}...", end=" ", flush=True)
|
||||||
|
audio, sr = load_stem(path)
|
||||||
|
voice_stems[name] = audio
|
||||||
|
print(f"{len(audio)/sr:.0f}s @ {sr}Hz")
|
||||||
|
|
||||||
|
if not voice_stems:
|
||||||
|
print("No voice stems found")
|
||||||
|
return
|
||||||
|
|
||||||
|
sr_val = sr
|
||||||
|
duration = max(len(a) for a in voice_stems.values()) / sr_val
|
||||||
|
print(f"\nTotal duration: {duration/60:.1f} min")
|
||||||
|
|
||||||
|
# Compute per-track RMS and peak blocks
|
||||||
|
track_rms = {}
|
||||||
|
track_peak = {}
|
||||||
|
for name, audio in voice_stems.items():
|
||||||
|
track_rms[name] = compute_rms_blocks(audio, sr_val)
|
||||||
|
track_peak[name] = compute_peak_blocks(audio, sr_val)
|
||||||
|
|
||||||
|
n_blocks = min(len(v) for v in track_peak.values())
|
||||||
|
|
||||||
|
# Detect gaps using same logic as Lua script (RMS for speaker ID, peak for silence)
|
||||||
|
min_voice_blocks = int(MIN_VOICE_SEC / BLOCK_SEC)
|
||||||
|
track_names = list(voice_stems.keys())
|
||||||
|
|
||||||
|
gaps = []
|
||||||
|
in_silence = False
|
||||||
|
silence_start = 0
|
||||||
|
track_before = None
|
||||||
|
last_active = None
|
||||||
|
voice_run = 0
|
||||||
|
voice_run_track = None
|
||||||
|
|
||||||
|
for i in range(n_blocks):
|
||||||
|
# Peak for silence detection
|
||||||
|
best_peak = max(track_peak[name][i] for name in track_names)
|
||||||
|
# RMS for speaker identification
|
||||||
|
best_rms = 0
|
||||||
|
best_track = None
|
||||||
|
for name in track_names:
|
||||||
|
r = track_rms[name][i]
|
||||||
|
if r > best_rms:
|
||||||
|
best_rms = r
|
||||||
|
best_track = name
|
||||||
|
|
||||||
|
all_silent = best_peak < THRESHOLD
|
||||||
|
|
||||||
|
if not all_silent:
|
||||||
|
last_active = best_track
|
||||||
|
|
||||||
|
if in_silence:
|
||||||
|
if all_silent:
|
||||||
|
voice_run = 0
|
||||||
|
voice_run_track = None
|
||||||
|
else:
|
||||||
|
if voice_run == 0:
|
||||||
|
voice_run_track = best_track
|
||||||
|
voice_run += 1
|
||||||
|
if voice_run >= min_voice_blocks:
|
||||||
|
voice_start_block = i - (voice_run - 1)
|
||||||
|
gap_start = silence_start * BLOCK_SEC
|
||||||
|
gap_end = voice_start_block * BLOCK_SEC
|
||||||
|
dur = gap_end - gap_start
|
||||||
|
if dur >= 0.5: # log gaps >= 0.5s
|
||||||
|
gaps.append({
|
||||||
|
"start": gap_start,
|
||||||
|
"end": gap_end,
|
||||||
|
"dur": dur,
|
||||||
|
"before": track_before or "?",
|
||||||
|
"after": voice_run_track or "?",
|
||||||
|
})
|
||||||
|
in_silence = False
|
||||||
|
voice_run = 0
|
||||||
|
voice_run_track = None
|
||||||
|
else:
|
||||||
|
if all_silent:
|
||||||
|
in_silence = True
|
||||||
|
silence_start = i
|
||||||
|
track_before = last_active
|
||||||
|
voice_run = 0
|
||||||
|
voice_run_track = None
|
||||||
|
|
||||||
|
# Trailing silence
|
||||||
|
if in_silence:
|
||||||
|
dur = (n_blocks - silence_start) * BLOCK_SEC
|
||||||
|
if dur >= 0.5:
|
||||||
|
gaps.append({
|
||||||
|
"start": silence_start * BLOCK_SEC,
|
||||||
|
"end": n_blocks * BLOCK_SEC,
|
||||||
|
"dur": dur,
|
||||||
|
"before": track_before or "?",
|
||||||
|
"after": "end",
|
||||||
|
})
|
||||||
|
|
||||||
|
if not gaps:
|
||||||
|
print("No gaps detected")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Categorize gaps
|
||||||
|
categories = {
|
||||||
|
"host_self": [], # Host -> Host
|
||||||
|
"host_to_caller": [], # Host -> Caller (TTS latency)
|
||||||
|
"caller_to_host": [], # Caller -> Host
|
||||||
|
"host_to_devon": [], # Host -> Devon (TTS latency)
|
||||||
|
"devon_to_host": [], # Devon -> Host
|
||||||
|
"caller_to_devon": [],# Caller -> Devon (interjection)
|
||||||
|
"devon_to_caller": [],# Devon -> Caller
|
||||||
|
"other": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
for g in gaps:
|
||||||
|
b, a = g["before"], g["after"]
|
||||||
|
if b == "host" and a == "host":
|
||||||
|
categories["host_self"].append(g)
|
||||||
|
elif b == "host" and a == "caller":
|
||||||
|
categories["host_to_caller"].append(g)
|
||||||
|
elif b == "caller" and a == "host":
|
||||||
|
categories["caller_to_host"].append(g)
|
||||||
|
elif b == "host" and a == "devon":
|
||||||
|
categories["host_to_devon"].append(g)
|
||||||
|
elif b == "devon" and a == "host":
|
||||||
|
categories["devon_to_host"].append(g)
|
||||||
|
elif b == "caller" and a == "devon":
|
||||||
|
categories["caller_to_devon"].append(g)
|
||||||
|
elif b == "devon" and a == "caller":
|
||||||
|
categories["devon_to_caller"].append(g)
|
||||||
|
else:
|
||||||
|
categories["other"].append(g)
|
||||||
|
|
||||||
|
# Print results
|
||||||
|
print(f"\n{'='*70}")
|
||||||
|
print(f"GAP ANALYSIS — {len(gaps)} gaps detected")
|
||||||
|
print(f"{'='*70}")
|
||||||
|
|
||||||
|
total_silence = sum(g["dur"] for g in gaps)
|
||||||
|
print(f"Total silence: {total_silence:.0f}s ({total_silence/60:.1f} min)")
|
||||||
|
print(f"Content after removal: ~{(duration - total_silence)/60:.1f} min")
|
||||||
|
|
||||||
|
for cat_name, cat_gaps in sorted(categories.items(), key=lambda x: -len(x[1])):
|
||||||
|
if not cat_gaps:
|
||||||
|
continue
|
||||||
|
durs = sorted([g["dur"] for g in cat_gaps])
|
||||||
|
print(f"\n--- {cat_name} ({len(cat_gaps)} gaps) ---")
|
||||||
|
print(f" Range: {durs[0]:.1f}s - {durs[-1]:.1f}s")
|
||||||
|
print(f" Median: {np.median(durs):.1f}s Mean: {np.mean(durs):.1f}s")
|
||||||
|
if len(durs) >= 5:
|
||||||
|
print(f" P25: {np.percentile(durs, 25):.1f}s P75: {np.percentile(durs, 75):.1f}s")
|
||||||
|
|
||||||
|
# Histogram
|
||||||
|
brackets = [(0, 1), (1, 2), (2, 3), (3, 5), (5, 8), (8, 12), (12, 18), (18, 30), (30, 60), (60, 999)]
|
||||||
|
print(f" Distribution:")
|
||||||
|
for lo, hi in brackets:
|
||||||
|
count = sum(1 for d in durs if lo <= d < hi)
|
||||||
|
if count > 0:
|
||||||
|
bar = "#" * count
|
||||||
|
label = f"{lo}-{hi}s" if hi < 999 else f"{lo}s+"
|
||||||
|
print(f" {label:>8s}: {bar} ({count})")
|
||||||
|
|
||||||
|
# Find natural clusters and suggest thresholds
|
||||||
|
print(f"\n{'='*70}")
|
||||||
|
print("SUGGESTED THRESHOLDS")
|
||||||
|
print(f"{'='*70}")
|
||||||
|
|
||||||
|
# For each Devon-involved category, find the gap between interjection and TTS gaps
|
||||||
|
devon_gaps = categories["host_to_devon"] + categories["devon_to_host"] + categories["caller_to_devon"] + categories["devon_to_caller"]
|
||||||
|
if devon_gaps:
|
||||||
|
devon_durs = sorted([g["dur"] for g in devon_gaps])
|
||||||
|
# Look for a natural break between short (interjection) and long (TTS) gaps
|
||||||
|
short = [d for d in devon_durs if d < 5]
|
||||||
|
long = [d for d in devon_durs if d >= 5]
|
||||||
|
if short and long:
|
||||||
|
suggested = (max(short) + min(long)) / 2
|
||||||
|
print(f"Devon threshold: {suggested:.1f}s (short gaps: {len(short)} up to {max(short):.1f}s, long gaps: {len(long)} from {min(long):.1f}s)")
|
||||||
|
elif short:
|
||||||
|
print(f"Devon threshold: {max(short) + 1:.1f}s (all gaps are short, max {max(short):.1f}s)")
|
||||||
|
else:
|
||||||
|
print(f"Devon threshold: 3.0s (all gaps are long, min {min(long):.1f}s)")
|
||||||
|
|
||||||
|
caller_gaps = categories["host_to_caller"] + categories["caller_to_host"]
|
||||||
|
if caller_gaps:
|
||||||
|
caller_durs = sorted([g["dur"] for g in caller_gaps])
|
||||||
|
short = [d for d in caller_durs if d < 5]
|
||||||
|
long = [d for d in caller_durs if d >= 5]
|
||||||
|
if short and long:
|
||||||
|
suggested = (max(short) + min(long)) / 2
|
||||||
|
print(f"Caller transition threshold: {suggested:.1f}s (short: {len(short)} up to {max(short):.1f}s, long: {len(long)} from {min(long):.1f}s)")
|
||||||
|
elif long:
|
||||||
|
print(f"Caller transition threshold: {min(long) - 1:.1f}s (all gaps >= {min(long):.1f}s)")
|
||||||
|
|
||||||
|
host_self = categories["host_self"]
|
||||||
|
if host_self:
|
||||||
|
host_durs = sorted([g["dur"] for g in host_self])
|
||||||
|
short = [d for d in host_durs if d < 5]
|
||||||
|
long = [d for d in host_durs if d >= 5]
|
||||||
|
if short and long:
|
||||||
|
suggested = (max(short) + min(long)) / 2
|
||||||
|
print(f"Same-speaker threshold: {suggested:.1f}s (short: {len(short)} up to {max(short):.1f}s, long: {len(long)} from {min(long):.1f}s)")
|
||||||
|
elif long:
|
||||||
|
print(f"Same-speaker threshold: {min(long) - 1:.1f}s (all gaps >= {min(long):.1f}s)")
|
||||||
|
|
||||||
|
all_durs = sorted([g["dur"] for g in gaps])
|
||||||
|
would_cut = [d for d in all_durs if d >= 3.0]
|
||||||
|
print(f"\nWith current thresholds (Devon=3s, others=6s):")
|
||||||
|
print(f" Would cut: ~{len(would_cut)} gaps, ~{sum(would_cut):.0f}s ({sum(would_cut)/60:.1f} min)")
|
||||||
|
print(f" Result: ~{(duration - sum(would_cut))/60:.1f} min")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python analyze_gaps.py <stems_dir>")
|
||||||
|
sys.exit(1)
|
||||||
|
analyze(Path(sys.argv[1]))
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
{
|
{
|
||||||
"input_device": 13,
|
"input_device": 13,
|
||||||
|
"input_device_name": "Babyface Pro (70793771)",
|
||||||
"input_channel": 1,
|
"input_channel": 1,
|
||||||
"output_device": 12,
|
"output_device": 12,
|
||||||
|
"output_device_name": "Radio Voice Mic",
|
||||||
"caller_channel": 3,
|
"caller_channel": 3,
|
||||||
"live_caller_channel": 9,
|
"live_caller_channel": 9,
|
||||||
"music_channel": 5,
|
"music_channel": 5,
|
||||||
"sfx_channel": 7,
|
"sfx_channel": 7,
|
||||||
"ad_channel": 11,
|
"ad_channel": 11,
|
||||||
|
"ident_channel": 15,
|
||||||
|
"monitor_device": null,
|
||||||
|
"monitor_device_name": null,
|
||||||
|
"monitor_channel": 1,
|
||||||
"phone_filter": false
|
"phone_filter": false
|
||||||
}
|
}
|
||||||
@@ -22,12 +22,30 @@ class Settings(BaseSettings):
|
|||||||
signalwire_phone: str = os.getenv("SIGNALWIRE_PHONE", "")
|
signalwire_phone: str = os.getenv("SIGNALWIRE_PHONE", "")
|
||||||
signalwire_stream_url: str = os.getenv("SIGNALWIRE_STREAM_URL", "")
|
signalwire_stream_url: str = os.getenv("SIGNALWIRE_STREAM_URL", "")
|
||||||
|
|
||||||
|
# Email (IMAP)
|
||||||
|
submissions_imap_host: str = os.getenv("SUBMISSIONS_IMAP_HOST", "")
|
||||||
|
submissions_imap_user: str = os.getenv("SUBMISSIONS_IMAP_USER", "")
|
||||||
|
submissions_imap_pass: str = os.getenv("SUBMISSIONS_IMAP_PASS", "")
|
||||||
|
|
||||||
# LLM Settings
|
# LLM Settings
|
||||||
llm_provider: str = "openrouter" # "openrouter" or "ollama"
|
llm_provider: str = "openrouter" # "openrouter" or "ollama"
|
||||||
openrouter_model: str = "anthropic/claude-sonnet-4-5"
|
openrouter_model: str = "anthropic/claude-sonnet-4-5" # primary/default model
|
||||||
ollama_model: str = "llama3.2"
|
ollama_model: str = "llama3.2"
|
||||||
ollama_host: str = "http://localhost:11434"
|
ollama_host: str = "http://localhost:11434"
|
||||||
|
|
||||||
|
# Per-category model routing — cheaper models for non-critical tasks
|
||||||
|
# Categories: caller_dialog, devon_monitor, devon_ask, background_gen,
|
||||||
|
# call_summary, news_summary, topic_gen, unknown
|
||||||
|
category_models: dict = {
|
||||||
|
"caller_dialog": "anthropic/claude-sonnet-4-5", # quality matters — this IS the show
|
||||||
|
"devon_ask": "google/gemini-2.5-flash", # Devon direct questions
|
||||||
|
"devon_monitor": "google/gemini-2.5-flash", # Devon polling — biggest cost saver
|
||||||
|
"background_gen": "google/gemini-2.5-flash", # JSON caller backgrounds
|
||||||
|
"call_summary": "google/gemini-2.5-flash", # post-call summaries
|
||||||
|
"news_summary": "google/gemini-2.5-flash", # news digests
|
||||||
|
"topic_gen": "google/gemini-2.5-flash", # topic generation
|
||||||
|
}
|
||||||
|
|
||||||
# TTS Settings
|
# TTS Settings
|
||||||
tts_provider: str = "inworld" # "kokoro", "elevenlabs", "inworld", "vits", or "bark"
|
tts_provider: str = "inworld" # "kokoro", "elevenlabs", "inworld", "vits", or "bark"
|
||||||
|
|
||||||
@@ -39,6 +57,7 @@ class Settings(BaseSettings):
|
|||||||
sounds_dir: Path = base_dir / "sounds"
|
sounds_dir: Path = base_dir / "sounds"
|
||||||
music_dir: Path = base_dir / "music"
|
music_dir: Path = base_dir / "music"
|
||||||
ads_dir: Path = base_dir / "ads"
|
ads_dir: Path = base_dir / "ads"
|
||||||
|
idents_dir: Path = base_dir / "idents"
|
||||||
sessions_dir: Path = base_dir / "sessions"
|
sessions_dir: Path = base_dir / "sessions"
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
|
|||||||
@@ -10,24 +10,68 @@ from typing import Optional, Callable
|
|||||||
import wave
|
import wave
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
# Settings file path
|
# Settings file path
|
||||||
SETTINGS_FILE = Path(__file__).parent.parent.parent / "audio_settings.json"
|
SETTINGS_FILE = Path(__file__).parent.parent.parent / "audio_settings.json"
|
||||||
|
|
||||||
|
# REAPER state file for dialog region markers
|
||||||
|
REAPER_STATE_FILE = "/tmp/reaper_state.txt"
|
||||||
|
|
||||||
|
def _write_reaper_state(state: str):
|
||||||
|
"""Write state to file. Uses a thread so it's safe from audio callbacks."""
|
||||||
|
def _write():
|
||||||
|
try:
|
||||||
|
with open(REAPER_STATE_FILE, "w") as f:
|
||||||
|
f.write(state)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
threading.Thread(target=_write, daemon=True).start()
|
||||||
|
|
||||||
|
|
||||||
class AudioService:
|
class AudioService:
|
||||||
"""Manages audio I/O with multi-channel support for Loopback routing"""
|
"""Manages audio I/O with multi-channel support for Loopback routing"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _find_device_by_name(name: str) -> Optional[int]:
|
||||||
|
"""Find a device index by name substring match. Returns None if not found."""
|
||||||
|
if not name:
|
||||||
|
return None
|
||||||
|
devices = sd.query_devices()
|
||||||
|
# Exact match first
|
||||||
|
for i, d in enumerate(devices):
|
||||||
|
if d["name"] == name:
|
||||||
|
return i
|
||||||
|
# Substring match
|
||||||
|
for i, d in enumerate(devices):
|
||||||
|
if name in d["name"]:
|
||||||
|
return i
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_device_name(device_id: Optional[int]) -> Optional[str]:
|
||||||
|
"""Get the name of a device by index."""
|
||||||
|
if device_id is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return sd.query_devices(device_id)["name"]
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Device configuration
|
# Device configuration
|
||||||
self.input_device: Optional[int] = None
|
self.input_device: Optional[int] = 13 # Radio Voice Mic (loopback input)
|
||||||
self.input_channel: int = 1 # 1-indexed channel
|
self.input_channel: int = 1 # 1-indexed channel
|
||||||
|
|
||||||
self.output_device: Optional[int] = None # Single output device (multi-channel)
|
self.output_device: Optional[int] = 12 # Radio Voice Mic (loopback output)
|
||||||
self.caller_channel: int = 1 # Channel for caller TTS
|
self.caller_channel: int = 3 # Channel for caller TTS
|
||||||
|
self.devon_channel: int = 17 # Channel for Devon (intern)
|
||||||
self.live_caller_channel: int = 9 # Channel for live caller audio
|
self.live_caller_channel: int = 9 # Channel for live caller audio
|
||||||
self.music_channel: int = 2 # Channel for music
|
self.music_channel: int = 5 # Channel for music
|
||||||
self.sfx_channel: int = 3 # Channel for SFX
|
self.sfx_channel: int = 3 # Channel for SFX
|
||||||
self.ad_channel: int = 11 # Channel for ads
|
self.ad_channel: int = 11 # Channel for ads
|
||||||
|
self.ident_channel: int = 15 # Channel for idents (stereo: ch 15+16)
|
||||||
|
self.monitor_device: Optional[int] = 14 # Babyface Pro (headphone monitoring)
|
||||||
|
self.monitor_channel: int = 1 # Channel for mic monitoring on monitor device
|
||||||
self.phone_filter: bool = False # Phone filter on caller voices
|
self.phone_filter: bool = False # Phone filter on caller voices
|
||||||
|
|
||||||
# Ad playback state
|
# Ad playback state
|
||||||
@@ -37,6 +81,13 @@ class AudioService:
|
|||||||
self._ad_position: int = 0
|
self._ad_position: int = 0
|
||||||
self._ad_playing: bool = False
|
self._ad_playing: bool = False
|
||||||
|
|
||||||
|
# Ident playback state
|
||||||
|
self._ident_stream: Optional[sd.OutputStream] = None
|
||||||
|
self._ident_data: Optional[np.ndarray] = None
|
||||||
|
self._ident_resampled: Optional[np.ndarray] = None
|
||||||
|
self._ident_position: int = 0
|
||||||
|
self._ident_playing: bool = False
|
||||||
|
|
||||||
# Recording state
|
# Recording state
|
||||||
self._recording = False
|
self._recording = False
|
||||||
self._record_thread: Optional[threading.Thread] = None
|
self._record_thread: Optional[threading.Thread] = None
|
||||||
@@ -78,6 +129,10 @@ class AudioService:
|
|||||||
self.input_sample_rate = 16000 # For Whisper
|
self.input_sample_rate = 16000 # For Whisper
|
||||||
self.output_sample_rate = 24000 # For TTS
|
self.output_sample_rate = 24000 # For TTS
|
||||||
|
|
||||||
|
# Mic monitor (input → monitor device passthrough)
|
||||||
|
self._monitor_stream: Optional[sd.OutputStream] = None
|
||||||
|
self._monitor_write: Optional[Callable] = None
|
||||||
|
|
||||||
# Stem recording (opt-in, attached via API)
|
# Stem recording (opt-in, attached via API)
|
||||||
self.stem_recorder = None
|
self.stem_recorder = None
|
||||||
self._stem_mic_stream: Optional[sd.InputStream] = None
|
self._stem_mic_stream: Optional[sd.InputStream] = None
|
||||||
@@ -85,37 +140,63 @@ class AudioService:
|
|||||||
# Load saved settings
|
# Load saved settings
|
||||||
self._load_settings()
|
self._load_settings()
|
||||||
|
|
||||||
|
def _resolve_device(self, data: dict, key: str) -> Optional[int]:
|
||||||
|
"""Resolve a device from settings: try name first, fall back to index."""
|
||||||
|
name_key = f"{key}_name"
|
||||||
|
name = data.get(name_key)
|
||||||
|
if name:
|
||||||
|
resolved = self._find_device_by_name(name)
|
||||||
|
if resolved is not None:
|
||||||
|
idx = data.get(key)
|
||||||
|
if idx is not None and resolved != idx:
|
||||||
|
print(f"[Audio] Device '{name}' moved: {idx} -> {resolved}")
|
||||||
|
return resolved
|
||||||
|
else:
|
||||||
|
print(f"[Audio] Warning: device '{name}' not found, falling back to index {data.get(key)}")
|
||||||
|
return data.get(key)
|
||||||
|
|
||||||
def _load_settings(self):
|
def _load_settings(self):
|
||||||
"""Load settings from disk"""
|
"""Load settings from disk, resolving device names to current indices"""
|
||||||
if SETTINGS_FILE.exists():
|
if SETTINGS_FILE.exists():
|
||||||
try:
|
try:
|
||||||
with open(SETTINGS_FILE) as f:
|
with open(SETTINGS_FILE) as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
self.input_device = data.get("input_device")
|
self.input_device = self._resolve_device(data, "input_device")
|
||||||
self.input_channel = data.get("input_channel", 1)
|
self.input_channel = data.get("input_channel", 1)
|
||||||
self.output_device = data.get("output_device")
|
self.output_device = self._resolve_device(data, "output_device")
|
||||||
self.caller_channel = data.get("caller_channel", 1)
|
self.caller_channel = data.get("caller_channel", 1)
|
||||||
|
self.devon_channel = data.get("devon_channel", 17)
|
||||||
self.live_caller_channel = data.get("live_caller_channel", 4)
|
self.live_caller_channel = data.get("live_caller_channel", 4)
|
||||||
self.music_channel = data.get("music_channel", 2)
|
self.music_channel = data.get("music_channel", 2)
|
||||||
self.sfx_channel = data.get("sfx_channel", 3)
|
self.sfx_channel = data.get("sfx_channel", 3)
|
||||||
self.ad_channel = data.get("ad_channel", 11)
|
self.ad_channel = data.get("ad_channel", 11)
|
||||||
|
self.ident_channel = data.get("ident_channel", 15)
|
||||||
|
self.monitor_device = self._resolve_device(data, "monitor_device")
|
||||||
|
self.monitor_channel = data.get("monitor_channel", 1)
|
||||||
self.phone_filter = data.get("phone_filter", False)
|
self.phone_filter = data.get("phone_filter", False)
|
||||||
print(f"Loaded audio settings: output={self.output_device}, channels={self.caller_channel}/{self.live_caller_channel}/{self.music_channel}/{self.sfx_channel}/ad:{self.ad_channel}, phone_filter={self.phone_filter}")
|
print(f"Loaded audio settings: input={self.input_device} ({self._get_device_name(self.input_device)}), output={self.output_device} ({self._get_device_name(self.output_device)}), monitor={self.monitor_device}, phone_filter={self.phone_filter}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to load audio settings: {e}")
|
print(f"Failed to load audio settings: {e}")
|
||||||
|
|
||||||
def _save_settings(self):
|
def _save_settings(self):
|
||||||
"""Save settings to disk"""
|
"""Save settings to disk with device names for stable resolution"""
|
||||||
try:
|
try:
|
||||||
data = {
|
data = {
|
||||||
"input_device": self.input_device,
|
"input_device": self.input_device,
|
||||||
|
"input_device_name": self._get_device_name(self.input_device),
|
||||||
"input_channel": self.input_channel,
|
"input_channel": self.input_channel,
|
||||||
"output_device": self.output_device,
|
"output_device": self.output_device,
|
||||||
|
"output_device_name": self._get_device_name(self.output_device),
|
||||||
"caller_channel": self.caller_channel,
|
"caller_channel": self.caller_channel,
|
||||||
|
"devon_channel": self.devon_channel,
|
||||||
"live_caller_channel": self.live_caller_channel,
|
"live_caller_channel": self.live_caller_channel,
|
||||||
"music_channel": self.music_channel,
|
"music_channel": self.music_channel,
|
||||||
"sfx_channel": self.sfx_channel,
|
"sfx_channel": self.sfx_channel,
|
||||||
"ad_channel": self.ad_channel,
|
"ad_channel": self.ad_channel,
|
||||||
|
"ident_channel": self.ident_channel,
|
||||||
|
"monitor_device": self.monitor_device,
|
||||||
|
"monitor_device_name": self._get_device_name(self.monitor_device),
|
||||||
|
"monitor_channel": self.monitor_channel,
|
||||||
"phone_filter": self.phone_filter,
|
"phone_filter": self.phone_filter,
|
||||||
}
|
}
|
||||||
with open(SETTINGS_FILE, "w") as f:
|
with open(SETTINGS_FILE, "w") as f:
|
||||||
@@ -144,10 +225,14 @@ class AudioService:
|
|||||||
input_channel: Optional[int] = None,
|
input_channel: Optional[int] = None,
|
||||||
output_device: Optional[int] = None,
|
output_device: Optional[int] = None,
|
||||||
caller_channel: Optional[int] = None,
|
caller_channel: Optional[int] = None,
|
||||||
|
devon_channel: Optional[int] = None,
|
||||||
live_caller_channel: Optional[int] = None,
|
live_caller_channel: Optional[int] = None,
|
||||||
music_channel: Optional[int] = None,
|
music_channel: Optional[int] = None,
|
||||||
sfx_channel: Optional[int] = None,
|
sfx_channel: Optional[int] = None,
|
||||||
ad_channel: Optional[int] = None,
|
ad_channel: Optional[int] = None,
|
||||||
|
ident_channel: Optional[int] = None,
|
||||||
|
monitor_device: Optional[int] = None,
|
||||||
|
monitor_channel: Optional[int] = None,
|
||||||
phone_filter: Optional[bool] = None
|
phone_filter: Optional[bool] = None
|
||||||
):
|
):
|
||||||
"""Configure audio devices and channels"""
|
"""Configure audio devices and channels"""
|
||||||
@@ -159,6 +244,8 @@ class AudioService:
|
|||||||
self.output_device = output_device
|
self.output_device = output_device
|
||||||
if caller_channel is not None:
|
if caller_channel is not None:
|
||||||
self.caller_channel = caller_channel
|
self.caller_channel = caller_channel
|
||||||
|
if devon_channel is not None:
|
||||||
|
self.devon_channel = devon_channel
|
||||||
if live_caller_channel is not None:
|
if live_caller_channel is not None:
|
||||||
self.live_caller_channel = live_caller_channel
|
self.live_caller_channel = live_caller_channel
|
||||||
if music_channel is not None:
|
if music_channel is not None:
|
||||||
@@ -167,6 +254,12 @@ class AudioService:
|
|||||||
self.sfx_channel = sfx_channel
|
self.sfx_channel = sfx_channel
|
||||||
if ad_channel is not None:
|
if ad_channel is not None:
|
||||||
self.ad_channel = ad_channel
|
self.ad_channel = ad_channel
|
||||||
|
if ident_channel is not None:
|
||||||
|
self.ident_channel = ident_channel
|
||||||
|
if monitor_device is not None:
|
||||||
|
self.monitor_device = monitor_device
|
||||||
|
if monitor_channel is not None:
|
||||||
|
self.monitor_channel = monitor_channel
|
||||||
if phone_filter is not None:
|
if phone_filter is not None:
|
||||||
self.phone_filter = phone_filter
|
self.phone_filter = phone_filter
|
||||||
|
|
||||||
@@ -180,10 +273,14 @@ class AudioService:
|
|||||||
"input_channel": self.input_channel,
|
"input_channel": self.input_channel,
|
||||||
"output_device": self.output_device,
|
"output_device": self.output_device,
|
||||||
"caller_channel": self.caller_channel,
|
"caller_channel": self.caller_channel,
|
||||||
|
"devon_channel": self.devon_channel,
|
||||||
"live_caller_channel": self.live_caller_channel,
|
"live_caller_channel": self.live_caller_channel,
|
||||||
"music_channel": self.music_channel,
|
"music_channel": self.music_channel,
|
||||||
"sfx_channel": self.sfx_channel,
|
"sfx_channel": self.sfx_channel,
|
||||||
"ad_channel": self.ad_channel,
|
"ad_channel": self.ad_channel,
|
||||||
|
"ident_channel": self.ident_channel,
|
||||||
|
"monitor_device": self.monitor_device,
|
||||||
|
"monitor_channel": self.monitor_channel,
|
||||||
"phone_filter": self.phone_filter,
|
"phone_filter": self.phone_filter,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,8 +426,8 @@ class AudioService:
|
|||||||
|
|
||||||
return audio
|
return audio
|
||||||
|
|
||||||
def play_caller_audio(self, audio_bytes: bytes, sample_rate: int = 24000):
|
def play_caller_audio(self, audio_bytes: bytes, sample_rate: int = 24000, stem_name: str = "caller", channel_override: int | None = None):
|
||||||
"""Play caller TTS audio to specific channel of output device (interruptible)"""
|
"""Play TTS audio to specific channel of output device (interruptible)"""
|
||||||
import librosa
|
import librosa
|
||||||
|
|
||||||
# Stop any existing caller audio
|
# Stop any existing caller audio
|
||||||
@@ -352,7 +449,8 @@ class AudioService:
|
|||||||
device_info = sd.query_devices(self.output_device)
|
device_info = sd.query_devices(self.output_device)
|
||||||
num_channels = device_info['max_output_channels']
|
num_channels = device_info['max_output_channels']
|
||||||
device_sr = int(device_info['default_samplerate'])
|
device_sr = int(device_info['default_samplerate'])
|
||||||
channel_idx = min(self.caller_channel, num_channels) - 1
|
ch = channel_override if channel_override is not None else self.caller_channel
|
||||||
|
channel_idx = min(ch, num_channels) - 1
|
||||||
|
|
||||||
# Resample if needed
|
# Resample if needed
|
||||||
if sample_rate != device_sr:
|
if sample_rate != device_sr:
|
||||||
@@ -365,7 +463,7 @@ class AudioService:
|
|||||||
multi_ch = np.zeros((len(audio), num_channels), dtype=np.float32)
|
multi_ch = np.zeros((len(audio), num_channels), dtype=np.float32)
|
||||||
multi_ch[:, channel_idx] = audio
|
multi_ch[:, channel_idx] = audio
|
||||||
|
|
||||||
print(f"Playing caller audio to device {self.output_device} ch {self.caller_channel} @ {device_sr}Hz")
|
print(f"Playing {stem_name} audio to device {self.output_device} ch {ch} @ {device_sr}Hz")
|
||||||
|
|
||||||
# Play in chunks so we can interrupt
|
# Play in chunks so we can interrupt
|
||||||
chunk_size = int(device_sr * 0.1) # 100ms chunks
|
chunk_size = int(device_sr * 0.1) # 100ms chunks
|
||||||
@@ -382,7 +480,7 @@ class AudioService:
|
|||||||
stream.write(multi_ch[pos:end])
|
stream.write(multi_ch[pos:end])
|
||||||
# Record each chunk as it plays so hangups cut the stem too
|
# Record each chunk as it plays so hangups cut the stem too
|
||||||
if self.stem_recorder:
|
if self.stem_recorder:
|
||||||
self.stem_recorder.write_sporadic("caller", audio[pos:end].copy(), device_sr)
|
self.stem_recorder.write_sporadic(stem_name, audio[pos:end].copy(), device_sr)
|
||||||
pos = end
|
pos = end
|
||||||
|
|
||||||
if self._caller_stop_event.is_set():
|
if self._caller_stop_event.is_set():
|
||||||
@@ -461,7 +559,7 @@ class AudioService:
|
|||||||
|
|
||||||
self._live_caller_write = write_audio
|
self._live_caller_write = write_audio
|
||||||
|
|
||||||
self._live_caller_stream = sd.OutputStream(
|
self._live_caller_stream = self._open_output_stream(
|
||||||
device=self.output_device,
|
device=self.output_device,
|
||||||
samplerate=device_sr,
|
samplerate=device_sr,
|
||||||
channels=num_channels,
|
channels=num_channels,
|
||||||
@@ -469,16 +567,15 @@ class AudioService:
|
|||||||
callback=callback,
|
callback=callback,
|
||||||
blocksize=1024,
|
blocksize=1024,
|
||||||
)
|
)
|
||||||
self._live_caller_stream.start()
|
|
||||||
print(f"[Audio] Live caller stream started on ch {self.live_caller_channel} @ {device_sr}Hz (prebuffer {prebuffer_samples} samples)")
|
print(f"[Audio] Live caller stream started on ch {self.live_caller_channel} @ {device_sr}Hz (prebuffer {prebuffer_samples} samples)")
|
||||||
|
|
||||||
def _stop_live_caller_stream(self):
|
def _stop_live_caller_stream(self):
|
||||||
"""Stop persistent live caller output stream"""
|
"""Stop persistent live caller output stream"""
|
||||||
if self._live_caller_stream:
|
if self._live_caller_stream:
|
||||||
self._live_caller_stream.stop()
|
stream = self._live_caller_stream
|
||||||
self._live_caller_stream.close()
|
|
||||||
self._live_caller_stream = None
|
self._live_caller_stream = None
|
||||||
self._live_caller_write = None
|
self._live_caller_write = None
|
||||||
|
self._close_stream(stream)
|
||||||
print("[Audio] Live caller stream stopped")
|
print("[Audio] Live caller stream stopped")
|
||||||
|
|
||||||
def route_real_caller_audio(self, pcm_data: bytes, sample_rate: int):
|
def route_real_caller_audio(self, pcm_data: bytes, sample_rate: int):
|
||||||
@@ -523,9 +620,9 @@ class AudioService:
|
|||||||
|
|
||||||
# Close stem_mic if active — this stream's callback handles stem recording too
|
# Close stem_mic if active — this stream's callback handles stem recording too
|
||||||
if self._stem_mic_stream is not None:
|
if self._stem_mic_stream is not None:
|
||||||
self._stem_mic_stream.stop()
|
stream = self._stem_mic_stream
|
||||||
self._stem_mic_stream.close()
|
|
||||||
self._stem_mic_stream = None
|
self._stem_mic_stream = None
|
||||||
|
self._close_stream(stream)
|
||||||
print("[Audio] Closed stem_mic (host stream takes over)")
|
print("[Audio] Closed stem_mic (host stream takes over)")
|
||||||
|
|
||||||
self._host_send_callback = send_callback
|
self._host_send_callback = send_callback
|
||||||
@@ -542,6 +639,9 @@ class AudioService:
|
|||||||
host_accum_samples = [0]
|
host_accum_samples = [0]
|
||||||
send_threshold = 1600 # 100ms at 16kHz
|
send_threshold = 1600 # 100ms at 16kHz
|
||||||
|
|
||||||
|
# Start mic monitor if monitor device is configured
|
||||||
|
self._start_monitor(device_sr)
|
||||||
|
|
||||||
def callback(indata, frames, time_info, status):
|
def callback(indata, frames, time_info, status):
|
||||||
# Capture for push-to-talk recording if active
|
# Capture for push-to-talk recording if active
|
||||||
if self._recording and self._recorded_audio is not None:
|
if self._recording and self._recorded_audio is not None:
|
||||||
@@ -551,6 +651,10 @@ class AudioService:
|
|||||||
if self.stem_recorder:
|
if self.stem_recorder:
|
||||||
self.stem_recorder.write("host", indata[:, record_channel].copy(), device_sr)
|
self.stem_recorder.write("host", indata[:, record_channel].copy(), device_sr)
|
||||||
|
|
||||||
|
# Mic monitor: send to headphone device
|
||||||
|
if self._monitor_write:
|
||||||
|
self._monitor_write(indata[:, record_channel].copy())
|
||||||
|
|
||||||
if not self._host_send_callback:
|
if not self._host_send_callback:
|
||||||
return
|
return
|
||||||
mono = indata[:, record_channel]
|
mono = indata[:, record_channel]
|
||||||
@@ -586,13 +690,89 @@ class AudioService:
|
|||||||
def stop_host_stream(self):
|
def stop_host_stream(self):
|
||||||
"""Stop host mic streaming and live caller output"""
|
"""Stop host mic streaming and live caller output"""
|
||||||
if self._host_stream:
|
if self._host_stream:
|
||||||
self._host_stream.stop()
|
stream = self._host_stream
|
||||||
self._host_stream.close()
|
|
||||||
self._host_stream = None
|
self._host_stream = None
|
||||||
self._host_send_callback = None
|
self._host_send_callback = None
|
||||||
|
self._close_stream(stream)
|
||||||
print("[Audio] Host mic streaming stopped")
|
print("[Audio] Host mic streaming stopped")
|
||||||
|
self._stop_monitor()
|
||||||
self._stop_live_caller_stream()
|
self._stop_live_caller_stream()
|
||||||
|
|
||||||
|
# --- Mic Monitor (input → headphone device) ---
|
||||||
|
|
||||||
|
def _start_monitor(self, input_sr: int):
|
||||||
|
"""Start mic monitor stream that routes input to monitor device"""
|
||||||
|
if self._monitor_stream is not None:
|
||||||
|
return
|
||||||
|
if self.monitor_device is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
device_info = sd.query_devices(self.monitor_device)
|
||||||
|
num_channels = device_info['max_output_channels']
|
||||||
|
device_sr = int(device_info['default_samplerate'])
|
||||||
|
channel_idx = min(self.monitor_channel, num_channels) - 1
|
||||||
|
|
||||||
|
# Ring buffer for cross-device routing
|
||||||
|
ring_size = int(device_sr * 2)
|
||||||
|
ring = np.zeros(ring_size, dtype=np.float32)
|
||||||
|
state = {"write_pos": 0, "read_pos": 0, "avail": 0}
|
||||||
|
|
||||||
|
# Precompute resample ratio (input device sr → monitor device sr)
|
||||||
|
resample_ratio = device_sr / input_sr
|
||||||
|
|
||||||
|
def write_audio(data):
|
||||||
|
# Resample if sample rates differ
|
||||||
|
if abs(resample_ratio - 1.0) > 0.01:
|
||||||
|
n_out = int(len(data) * resample_ratio)
|
||||||
|
indices = np.linspace(0, len(data) - 1, n_out).astype(int)
|
||||||
|
data = data[indices]
|
||||||
|
n = len(data)
|
||||||
|
wp = state["write_pos"]
|
||||||
|
if wp + n <= ring_size:
|
||||||
|
ring[wp:wp + n] = data
|
||||||
|
else:
|
||||||
|
first = ring_size - wp
|
||||||
|
ring[wp:] = data[:first]
|
||||||
|
ring[:n - first] = data[first:]
|
||||||
|
state["write_pos"] = (wp + n) % ring_size
|
||||||
|
state["avail"] += n
|
||||||
|
|
||||||
|
def callback(outdata, frames, time_info, status):
|
||||||
|
outdata.fill(0)
|
||||||
|
avail = state["avail"]
|
||||||
|
if avail < frames:
|
||||||
|
return
|
||||||
|
rp = state["read_pos"]
|
||||||
|
if rp + frames <= ring_size:
|
||||||
|
outdata[:frames, channel_idx] = ring[rp:rp + frames]
|
||||||
|
else:
|
||||||
|
first = ring_size - rp
|
||||||
|
outdata[:first, channel_idx] = ring[rp:]
|
||||||
|
outdata[first:frames, channel_idx] = ring[:frames - first]
|
||||||
|
state["read_pos"] = (rp + frames) % ring_size
|
||||||
|
state["avail"] -= frames
|
||||||
|
|
||||||
|
self._monitor_write = write_audio
|
||||||
|
self._monitor_stream = sd.OutputStream(
|
||||||
|
device=self.monitor_device,
|
||||||
|
samplerate=device_sr,
|
||||||
|
channels=num_channels,
|
||||||
|
dtype=np.float32,
|
||||||
|
blocksize=1024,
|
||||||
|
callback=callback,
|
||||||
|
)
|
||||||
|
self._monitor_stream.start()
|
||||||
|
print(f"[Audio] Mic monitor started (device {self.monitor_device} ch {self.monitor_channel} @ {device_sr}Hz)")
|
||||||
|
|
||||||
|
def _stop_monitor(self):
|
||||||
|
"""Stop mic monitor stream"""
|
||||||
|
if self._monitor_stream:
|
||||||
|
stream = self._monitor_stream
|
||||||
|
self._monitor_stream = None
|
||||||
|
self._monitor_write = None
|
||||||
|
self._close_stream(stream)
|
||||||
|
print("[Audio] Mic monitor stopped")
|
||||||
|
|
||||||
# --- Music Playback ---
|
# --- Music Playback ---
|
||||||
|
|
||||||
def load_music(self, file_path: str) -> bool:
|
def load_music(self, file_path: str) -> bool:
|
||||||
@@ -765,7 +945,7 @@ class AudioService:
|
|||||||
self.stem_recorder.write_sporadic("music", mono_out.copy(), device_sr)
|
self.stem_recorder.write_sporadic("music", mono_out.copy(), device_sr)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._music_stream = sd.OutputStream(
|
self._music_stream = self._open_output_stream(
|
||||||
device=device,
|
device=device,
|
||||||
channels=num_channels,
|
channels=num_channels,
|
||||||
samplerate=device_sr,
|
samplerate=device_sr,
|
||||||
@@ -773,28 +953,68 @@ class AudioService:
|
|||||||
callback=callback,
|
callback=callback,
|
||||||
blocksize=2048
|
blocksize=2048
|
||||||
)
|
)
|
||||||
self._music_stream.start()
|
|
||||||
print(f"Music playback started on ch {self.music_channel} @ {device_sr}Hz")
|
print(f"Music playback started on ch {self.music_channel} @ {device_sr}Hz")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Music playback error: {e}")
|
print(f"Music playback error: {e}")
|
||||||
self._music_playing = False
|
self._music_playing = False
|
||||||
|
|
||||||
|
def _refresh_devices(self):
|
||||||
|
"""Re-initialize PortAudio to pick up device changes, then re-resolve settings."""
|
||||||
|
try:
|
||||||
|
sd._terminate()
|
||||||
|
sd._initialize()
|
||||||
|
print("[Audio] PortAudio re-initialized")
|
||||||
|
self._load_settings()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[Audio] PortAudio refresh failed: {e}")
|
||||||
|
|
||||||
|
def _open_output_stream(self, **kwargs) -> sd.OutputStream:
|
||||||
|
"""Open an OutputStream with one retry after refreshing PortAudio on failure."""
|
||||||
|
try:
|
||||||
|
stream = sd.OutputStream(**kwargs)
|
||||||
|
stream.start()
|
||||||
|
return stream
|
||||||
|
except Exception as first_err:
|
||||||
|
print(f"[Audio] Stream open failed ({first_err}), refreshing devices...")
|
||||||
|
self._refresh_devices()
|
||||||
|
# Update device/channel info from refreshed settings
|
||||||
|
if kwargs.get("device") == self.output_device or "device" in kwargs:
|
||||||
|
device_info = sd.query_devices(self.output_device)
|
||||||
|
kwargs["device"] = self.output_device
|
||||||
|
kwargs["channels"] = device_info["max_output_channels"]
|
||||||
|
kwargs["samplerate"] = int(device_info["default_samplerate"])
|
||||||
|
stream = sd.OutputStream(**kwargs)
|
||||||
|
stream.start()
|
||||||
|
return stream
|
||||||
|
|
||||||
|
def _close_stream(self, stream):
|
||||||
|
"""Safely close a sounddevice stream, ignoring double-close errors"""
|
||||||
|
if stream is None:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
stream.stop()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
stream.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
def stop_music(self, fade_duration: float = 2.0):
|
def stop_music(self, fade_duration: float = 2.0):
|
||||||
"""Stop music playback with fade out"""
|
"""Stop music playback with fade out"""
|
||||||
if not self._music_playing or not self._music_stream:
|
if not self._music_playing or not self._music_stream:
|
||||||
self._music_playing = False
|
self._music_playing = False
|
||||||
if self._music_stream:
|
stream = self._music_stream
|
||||||
self._music_stream.stop()
|
|
||||||
self._music_stream.close()
|
|
||||||
self._music_stream = None
|
self._music_stream = None
|
||||||
|
self._close_stream(stream)
|
||||||
self._music_position = 0
|
self._music_position = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
if fade_duration <= 0:
|
if fade_duration <= 0:
|
||||||
self._music_playing = False
|
self._music_playing = False
|
||||||
self._music_stream.stop()
|
stream = self._music_stream
|
||||||
self._music_stream.close()
|
|
||||||
self._music_stream = None
|
self._music_stream = None
|
||||||
|
self._close_stream(stream)
|
||||||
self._music_position = 0
|
self._music_position = 0
|
||||||
print("Music stopped")
|
print("Music stopped")
|
||||||
return
|
return
|
||||||
@@ -803,6 +1023,10 @@ class AudioService:
|
|||||||
original_volume = self._music_volume
|
original_volume = self._music_volume
|
||||||
steps = 20
|
steps = 20
|
||||||
step_time = fade_duration / steps
|
step_time = fade_duration / steps
|
||||||
|
# Capture stream reference locally so the fade thread closes THIS stream,
|
||||||
|
# not whatever self._music_stream points to later
|
||||||
|
fade_stream = self._music_stream
|
||||||
|
self._music_stream = None
|
||||||
|
|
||||||
def _fade():
|
def _fade():
|
||||||
for i in range(steps):
|
for i in range(steps):
|
||||||
@@ -812,10 +1036,7 @@ class AudioService:
|
|||||||
import time
|
import time
|
||||||
time.sleep(step_time)
|
time.sleep(step_time)
|
||||||
self._music_playing = False
|
self._music_playing = False
|
||||||
if self._music_stream:
|
self._close_stream(fade_stream)
|
||||||
self._music_stream.stop()
|
|
||||||
self._music_stream.close()
|
|
||||||
self._music_stream = None
|
|
||||||
self._music_position = 0
|
self._music_position = 0
|
||||||
self._music_volume = original_volume
|
self._music_volume = original_volume
|
||||||
print("Music faded out and stopped")
|
print("Music faded out and stopped")
|
||||||
@@ -832,6 +1053,7 @@ class AudioService:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.stop_ad()
|
self.stop_ad()
|
||||||
|
self.stop_ident()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
audio, sr = librosa.load(str(path), sr=self.output_sample_rate, mono=True)
|
audio, sr = librosa.load(str(path), sr=self.output_sample_rate, mono=True)
|
||||||
@@ -842,6 +1064,7 @@ class AudioService:
|
|||||||
|
|
||||||
self._ad_playing = True
|
self._ad_playing = True
|
||||||
self._ad_position = 0
|
self._ad_position = 0
|
||||||
|
_write_reaper_state("ad")
|
||||||
|
|
||||||
if self.output_device is None:
|
if self.output_device is None:
|
||||||
num_channels = 2
|
num_channels = 2
|
||||||
@@ -879,9 +1102,10 @@ class AudioService:
|
|||||||
outdata[:remaining, channel_idx] = self._ad_resampled[self._ad_position:]
|
outdata[:remaining, channel_idx] = self._ad_resampled[self._ad_position:]
|
||||||
# Ad finished — no loop
|
# Ad finished — no loop
|
||||||
self._ad_playing = False
|
self._ad_playing = False
|
||||||
|
_write_reaper_state("dialog")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._ad_stream = sd.OutputStream(
|
self._ad_stream = self._open_output_stream(
|
||||||
device=device,
|
device=device,
|
||||||
channels=num_channels,
|
channels=num_channels,
|
||||||
samplerate=device_sr,
|
samplerate=device_sr,
|
||||||
@@ -889,7 +1113,6 @@ class AudioService:
|
|||||||
callback=callback,
|
callback=callback,
|
||||||
blocksize=2048
|
blocksize=2048
|
||||||
)
|
)
|
||||||
self._ad_stream.start()
|
|
||||||
print(f"Ad playback started on ch {self.ad_channel} @ {device_sr}Hz")
|
print(f"Ad playback started on ch {self.ad_channel} @ {device_sr}Hz")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Ad playback error: {e}")
|
print(f"Ad playback error: {e}")
|
||||||
@@ -897,13 +1120,121 @@ class AudioService:
|
|||||||
|
|
||||||
def stop_ad(self):
|
def stop_ad(self):
|
||||||
"""Stop ad playback"""
|
"""Stop ad playback"""
|
||||||
|
was_playing = self._ad_playing
|
||||||
self._ad_playing = False
|
self._ad_playing = False
|
||||||
|
if was_playing:
|
||||||
|
_write_reaper_state("dialog")
|
||||||
if self._ad_stream:
|
if self._ad_stream:
|
||||||
self._ad_stream.stop()
|
stream = self._ad_stream
|
||||||
self._ad_stream.close()
|
|
||||||
self._ad_stream = None
|
self._ad_stream = None
|
||||||
|
self._close_stream(stream)
|
||||||
self._ad_position = 0
|
self._ad_position = 0
|
||||||
|
|
||||||
|
def play_ident(self, file_path: str):
|
||||||
|
"""Load and play an ident file once (no loop) in stereo on ident_channel/ident_channel+1"""
|
||||||
|
import librosa
|
||||||
|
|
||||||
|
path = Path(file_path)
|
||||||
|
if not path.exists():
|
||||||
|
print(f"Ident file not found: {file_path}")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.stop_ident()
|
||||||
|
self.stop_ad()
|
||||||
|
|
||||||
|
try:
|
||||||
|
audio, sr = librosa.load(str(path), sr=self.output_sample_rate, mono=False)
|
||||||
|
if audio.ndim == 1:
|
||||||
|
# Mono file — duplicate to stereo
|
||||||
|
audio = np.stack([audio, audio])
|
||||||
|
audio = audio.astype(np.float32) # shape: (2, samples)
|
||||||
|
self._ident_data = audio
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to load ident: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
self._ident_playing = True
|
||||||
|
self._ident_position = 0
|
||||||
|
_write_reaper_state("ident")
|
||||||
|
print(f"Ident loaded: shape={self._ident_data.shape}, max={np.max(np.abs(self._ident_data)):.4f}")
|
||||||
|
|
||||||
|
if self.output_device is None:
|
||||||
|
num_channels = 2
|
||||||
|
device = None
|
||||||
|
device_sr = self.output_sample_rate
|
||||||
|
ch_l = 0
|
||||||
|
ch_r = 1
|
||||||
|
else:
|
||||||
|
device_info = sd.query_devices(self.output_device)
|
||||||
|
num_channels = device_info['max_output_channels']
|
||||||
|
device_sr = int(device_info['default_samplerate'])
|
||||||
|
device = self.output_device
|
||||||
|
ch_l = min(self.ident_channel, num_channels) - 1
|
||||||
|
ch_r = min(self.ident_channel + 1, num_channels) - 1
|
||||||
|
|
||||||
|
if self.output_sample_rate != device_sr:
|
||||||
|
self._ident_resampled = np.stack([
|
||||||
|
librosa.resample(self._ident_data[0], orig_sr=self.output_sample_rate, target_sr=device_sr),
|
||||||
|
librosa.resample(self._ident_data[1], orig_sr=self.output_sample_rate, target_sr=device_sr),
|
||||||
|
]).astype(np.float32)
|
||||||
|
else:
|
||||||
|
self._ident_resampled = self._ident_data
|
||||||
|
|
||||||
|
_cb_count = [0]
|
||||||
|
def callback(outdata, frames, time_info, status):
|
||||||
|
outdata[:] = 0
|
||||||
|
if not self._ident_playing or self._ident_resampled is None:
|
||||||
|
if _cb_count[0] == 0:
|
||||||
|
print(f"Ident callback: not playing (playing={self._ident_playing}, data={'yes' if self._ident_resampled is not None else 'no'})")
|
||||||
|
return
|
||||||
|
|
||||||
|
n_samples = self._ident_resampled.shape[1]
|
||||||
|
remaining = n_samples - self._ident_position
|
||||||
|
if remaining >= frames:
|
||||||
|
chunk_l = self._ident_resampled[0, self._ident_position:self._ident_position + frames]
|
||||||
|
chunk_r = self._ident_resampled[1, self._ident_position:self._ident_position + frames]
|
||||||
|
outdata[:, ch_l] = chunk_l
|
||||||
|
outdata[:, ch_r] = chunk_r
|
||||||
|
_cb_count[0] += 1
|
||||||
|
if _cb_count[0] == 1:
|
||||||
|
print(f"Ident callback delivering audio: ch_l={ch_l}, ch_r={ch_r}, max={max(np.max(np.abs(chunk_l)), np.max(np.abs(chunk_r))):.4f}")
|
||||||
|
if self.stem_recorder:
|
||||||
|
mono_mix = (chunk_l + chunk_r) * 0.5
|
||||||
|
self.stem_recorder.write_sporadic("idents", mono_mix.copy(), device_sr)
|
||||||
|
self._ident_position += frames
|
||||||
|
else:
|
||||||
|
if remaining > 0:
|
||||||
|
outdata[:remaining, ch_l] = self._ident_resampled[0, self._ident_position:]
|
||||||
|
outdata[:remaining, ch_r] = self._ident_resampled[1, self._ident_position:]
|
||||||
|
self._ident_playing = False
|
||||||
|
_write_reaper_state("dialog")
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._ident_stream = self._open_output_stream(
|
||||||
|
device=device,
|
||||||
|
channels=num_channels,
|
||||||
|
samplerate=device_sr,
|
||||||
|
dtype=np.float32,
|
||||||
|
callback=callback,
|
||||||
|
blocksize=2048
|
||||||
|
)
|
||||||
|
print(f"Ident playback started on ch {ch_l+1}/{ch_r+1} (idx {ch_l}/{ch_r}) of {num_channels} channels @ {device_sr}Hz, device={device}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ident playback error: {e}")
|
||||||
|
self._ident_playing = False
|
||||||
|
|
||||||
|
def stop_ident(self):
|
||||||
|
"""Stop ident playback"""
|
||||||
|
was_playing = self._ident_playing
|
||||||
|
self._ident_playing = False
|
||||||
|
if was_playing:
|
||||||
|
_write_reaper_state("dialog")
|
||||||
|
if self._ident_stream:
|
||||||
|
stream = self._ident_stream
|
||||||
|
self._ident_stream = None
|
||||||
|
self._close_stream(stream)
|
||||||
|
self._ident_position = 0
|
||||||
|
|
||||||
def set_music_volume(self, volume: float):
|
def set_music_volume(self, volume: float):
|
||||||
"""Set music volume (0.0 to 1.0)"""
|
"""Set music volume (0.0 to 1.0)"""
|
||||||
self._music_volume = max(0.0, min(1.0, volume))
|
self._music_volume = max(0.0, min(1.0, volume))
|
||||||
@@ -926,6 +1257,7 @@ class AudioService:
|
|||||||
|
|
||||||
if self.output_device is None:
|
if self.output_device is None:
|
||||||
audio, sr = librosa.load(str(path), sr=None, mono=True)
|
audio, sr = librosa.load(str(path), sr=None, mono=True)
|
||||||
|
audio = audio.astype(np.float32)
|
||||||
audio = self._apply_fade(audio, sr)
|
audio = self._apply_fade(audio, sr)
|
||||||
def play():
|
def play():
|
||||||
# Use a dedicated stream instead of sd.play()
|
# Use a dedicated stream instead of sd.play()
|
||||||
@@ -938,6 +1270,7 @@ class AudioService:
|
|||||||
channel_idx = min(self.sfx_channel, num_channels) - 1
|
channel_idx = min(self.sfx_channel, num_channels) - 1
|
||||||
|
|
||||||
audio, _ = librosa.load(str(path), sr=device_sr, mono=True)
|
audio, _ = librosa.load(str(path), sr=device_sr, mono=True)
|
||||||
|
audio = audio.astype(np.float32)
|
||||||
audio = self._apply_fade(audio, device_sr)
|
audio = self._apply_fade(audio, device_sr)
|
||||||
|
|
||||||
# Stem recording: sfx
|
# Stem recording: sfx
|
||||||
@@ -981,9 +1314,13 @@ class AudioService:
|
|||||||
device_sr = int(device_info['default_samplerate'])
|
device_sr = int(device_info['default_samplerate'])
|
||||||
record_channel = min(self.input_channel, max_channels) - 1
|
record_channel = min(self.input_channel, max_channels) - 1
|
||||||
|
|
||||||
|
self._start_monitor(device_sr)
|
||||||
|
|
||||||
def callback(indata, frames, time_info, status):
|
def callback(indata, frames, time_info, status):
|
||||||
if self.stem_recorder:
|
if self.stem_recorder:
|
||||||
self.stem_recorder.write("host", indata[:, record_channel].copy(), device_sr)
|
self.stem_recorder.write("host", indata[:, record_channel].copy(), device_sr)
|
||||||
|
if self._monitor_write:
|
||||||
|
self._monitor_write(indata[:, record_channel].copy())
|
||||||
|
|
||||||
self._stem_mic_stream = sd.InputStream(
|
self._stem_mic_stream = sd.InputStream(
|
||||||
device=self.input_device,
|
device=self.input_device,
|
||||||
@@ -999,10 +1336,11 @@ class AudioService:
|
|||||||
def stop_stem_mic(self):
|
def stop_stem_mic(self):
|
||||||
"""Stop the persistent stem mic capture."""
|
"""Stop the persistent stem mic capture."""
|
||||||
if self._stem_mic_stream:
|
if self._stem_mic_stream:
|
||||||
self._stem_mic_stream.stop()
|
stream = self._stem_mic_stream
|
||||||
self._stem_mic_stream.close()
|
|
||||||
self._stem_mic_stream = None
|
self._stem_mic_stream = None
|
||||||
|
self._close_stream(stream)
|
||||||
print("[StemRecorder] Host mic capture stopped")
|
print("[StemRecorder] Host mic capture stopped")
|
||||||
|
self._stop_monitor()
|
||||||
|
|
||||||
|
|
||||||
# Global instance
|
# Global instance
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
"""Avatar service — fetches deterministic face photos from randomuser.me"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
AVATAR_DIR = Path(__file__).parent.parent.parent / "data" / "avatars"
|
||||||
|
|
||||||
|
|
||||||
|
class AvatarService:
|
||||||
|
def __init__(self):
|
||||||
|
self._client: httpx.AsyncClient | None = None
|
||||||
|
AVATAR_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client(self) -> httpx.AsyncClient:
|
||||||
|
if self._client is None or self._client.is_closed:
|
||||||
|
self._client = httpx.AsyncClient(timeout=10.0)
|
||||||
|
return self._client
|
||||||
|
|
||||||
|
def get_path(self, name: str) -> Path | None:
|
||||||
|
path = AVATAR_DIR / f"{name}.jpg"
|
||||||
|
return path if path.exists() else None
|
||||||
|
|
||||||
|
async def get_or_fetch(self, name: str, gender: str = "male") -> Path:
|
||||||
|
"""Get cached avatar or fetch from randomuser.me. Returns file path."""
|
||||||
|
g = "female" if gender.lower().startswith("f") else "male"
|
||||||
|
path = AVATAR_DIR / f"{name}.jpg"
|
||||||
|
# Check for gender mismatch marker — re-fetch if gender changed
|
||||||
|
marker = AVATAR_DIR / f"{name}.gender"
|
||||||
|
if path.exists():
|
||||||
|
cached_gender = marker.read_text().strip() if marker.exists() else None
|
||||||
|
if cached_gender == g:
|
||||||
|
return path
|
||||||
|
# Gender mismatch or no marker — re-fetch
|
||||||
|
path.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
seed = f"{name.lower().replace(' ', '_')}_{g}"
|
||||||
|
resp = await self.client.get(
|
||||||
|
"https://randomuser.me/api/",
|
||||||
|
params={"gender": g, "seed": seed},
|
||||||
|
timeout=8.0,
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
data = resp.json()
|
||||||
|
photo_url = data["results"][0]["picture"]["large"]
|
||||||
|
|
||||||
|
photo_resp = await self.client.get(photo_url, timeout=8.0)
|
||||||
|
photo_resp.raise_for_status()
|
||||||
|
|
||||||
|
path.write_bytes(photo_resp.content)
|
||||||
|
marker.write_text(g)
|
||||||
|
print(f"[Avatar] Fetched avatar for {name} ({g})")
|
||||||
|
return path
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[Avatar] Failed to fetch for {name}: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def prefetch_batch(self, callers: list[dict]):
|
||||||
|
"""Fetch avatars for multiple callers in parallel.
|
||||||
|
Each dict should have 'name' and 'gender' keys."""
|
||||||
|
tasks = []
|
||||||
|
for caller in callers:
|
||||||
|
name = caller.get("name", "")
|
||||||
|
gender = caller.get("gender", "male")
|
||||||
|
if name and not (AVATAR_DIR / f"{name}.jpg").exists():
|
||||||
|
tasks.append(self.get_or_fetch(name, gender))
|
||||||
|
|
||||||
|
if not tasks:
|
||||||
|
return
|
||||||
|
|
||||||
|
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||||
|
fetched = sum(1 for r in results if not isinstance(r, Exception))
|
||||||
|
failed = sum(1 for r in results if isinstance(r, Exception))
|
||||||
|
if fetched:
|
||||||
|
print(f"[Avatar] Pre-fetched {fetched} avatars{f', {failed} failed' if failed else ''}")
|
||||||
|
|
||||||
|
async def ensure_devon(self):
|
||||||
|
"""Pre-fetch Devon's avatar on startup."""
|
||||||
|
try:
|
||||||
|
await self.get_or_fetch("Devon", "male")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
avatar_service = AvatarService()
|
||||||
@@ -0,0 +1,364 @@
|
|||||||
|
"""Cost tracking for LLM and TTS API calls during podcast sessions"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
from dataclasses import dataclass, field, asdict
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LLMCallRecord:
|
||||||
|
timestamp: float
|
||||||
|
category: str
|
||||||
|
model: str
|
||||||
|
prompt_tokens: int
|
||||||
|
completion_tokens: int
|
||||||
|
total_tokens: int
|
||||||
|
cost_usd: float
|
||||||
|
caller_name: str
|
||||||
|
max_tokens_requested: int
|
||||||
|
latency_ms: float
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TTSCallRecord:
|
||||||
|
timestamp: float
|
||||||
|
provider: str
|
||||||
|
voice: str
|
||||||
|
char_count: int
|
||||||
|
cost_usd: float
|
||||||
|
|
||||||
|
|
||||||
|
# OpenRouter pricing per 1M tokens (as of March 2026)
|
||||||
|
OPENROUTER_PRICING = {
|
||||||
|
"anthropic/claude-sonnet-4-5": {"prompt": 3.00, "completion": 15.00},
|
||||||
|
"anthropic/claude-haiku-4.5": {"prompt": 0.80, "completion": 4.00},
|
||||||
|
"anthropic/claude-3-haiku": {"prompt": 0.25, "completion": 1.25},
|
||||||
|
"x-ai/grok-4-fast": {"prompt": 5.00, "completion": 15.00},
|
||||||
|
"minimax/minimax-m2-her": {"prompt": 0.50, "completion": 1.50},
|
||||||
|
"mistralai/mistral-small-creative": {"prompt": 0.20, "completion": 0.60},
|
||||||
|
"deepseek/deepseek-v3.2": {"prompt": 0.14, "completion": 0.28},
|
||||||
|
"google/gemini-2.5-flash": {"prompt": 0.15, "completion": 0.60},
|
||||||
|
"google/gemini-flash-1.5": {"prompt": 0.075, "completion": 0.30},
|
||||||
|
"openai/gpt-4o-mini": {"prompt": 0.15, "completion": 0.60},
|
||||||
|
"openai/gpt-4o": {"prompt": 2.50, "completion": 10.00},
|
||||||
|
"meta-llama/llama-3.1-8b-instruct": {"prompt": 0.06, "completion": 0.06},
|
||||||
|
}
|
||||||
|
|
||||||
|
# TTS pricing per character
|
||||||
|
TTS_PRICING = {
|
||||||
|
"inworld": 0.000015,
|
||||||
|
"elevenlabs": 0.000030,
|
||||||
|
"kokoro": 0.0,
|
||||||
|
"f5tts": 0.0,
|
||||||
|
"chattts": 0.0,
|
||||||
|
"styletts2": 0.0,
|
||||||
|
"vits": 0.0,
|
||||||
|
"bark": 0.0,
|
||||||
|
"piper": 0.0,
|
||||||
|
"edge": 0.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _calc_llm_cost(model: str, prompt_tokens: int, completion_tokens: int) -> float:
|
||||||
|
pricing = OPENROUTER_PRICING.get(model)
|
||||||
|
if not pricing:
|
||||||
|
return 0.0
|
||||||
|
return (prompt_tokens * pricing["prompt"] + completion_tokens * pricing["completion"]) / 1_000_000
|
||||||
|
|
||||||
|
|
||||||
|
def _calc_tts_cost(provider: str, char_count: int) -> float:
|
||||||
|
rate = TTS_PRICING.get(provider, 0.0)
|
||||||
|
return char_count * rate
|
||||||
|
|
||||||
|
|
||||||
|
class CostTracker:
|
||||||
|
def __init__(self):
|
||||||
|
self.llm_records: list[LLMCallRecord] = []
|
||||||
|
self.tts_records: list[TTSCallRecord] = []
|
||||||
|
# Running totals for fast get_live_summary()
|
||||||
|
self._llm_cost: float = 0.0
|
||||||
|
self._tts_cost: float = 0.0
|
||||||
|
self._llm_calls: int = 0
|
||||||
|
self._prompt_tokens: int = 0
|
||||||
|
self._completion_tokens: int = 0
|
||||||
|
self._total_tokens: int = 0
|
||||||
|
self._by_category: dict[str, dict] = {}
|
||||||
|
|
||||||
|
def record_llm_call(
|
||||||
|
self,
|
||||||
|
category: str,
|
||||||
|
model: str,
|
||||||
|
usage_data: dict,
|
||||||
|
max_tokens: int = 0,
|
||||||
|
latency_ms: float = 0.0,
|
||||||
|
caller_name: str = "",
|
||||||
|
):
|
||||||
|
prompt_tokens = usage_data.get("prompt_tokens", 0)
|
||||||
|
completion_tokens = usage_data.get("completion_tokens", 0)
|
||||||
|
total_tokens = usage_data.get("total_tokens", 0) or (prompt_tokens + completion_tokens)
|
||||||
|
cost = _calc_llm_cost(model, prompt_tokens, completion_tokens)
|
||||||
|
|
||||||
|
if not OPENROUTER_PRICING.get(model) and total_tokens > 0:
|
||||||
|
print(f"[Costs] Unknown model pricing: {model} ({total_tokens} tokens, cost unknown)")
|
||||||
|
|
||||||
|
record = LLMCallRecord(
|
||||||
|
timestamp=time.time(),
|
||||||
|
category=category,
|
||||||
|
model=model,
|
||||||
|
prompt_tokens=prompt_tokens,
|
||||||
|
completion_tokens=completion_tokens,
|
||||||
|
total_tokens=total_tokens,
|
||||||
|
cost_usd=cost,
|
||||||
|
caller_name=caller_name,
|
||||||
|
max_tokens_requested=max_tokens,
|
||||||
|
latency_ms=latency_ms,
|
||||||
|
)
|
||||||
|
self.llm_records.append(record)
|
||||||
|
|
||||||
|
# Update running totals
|
||||||
|
self._llm_cost += cost
|
||||||
|
self._llm_calls += 1
|
||||||
|
self._prompt_tokens += prompt_tokens
|
||||||
|
self._completion_tokens += completion_tokens
|
||||||
|
self._total_tokens += total_tokens
|
||||||
|
|
||||||
|
cat = self._by_category.setdefault(category, {"cost": 0.0, "calls": 0, "tokens": 0})
|
||||||
|
cat["cost"] += cost
|
||||||
|
cat["calls"] += 1
|
||||||
|
cat["tokens"] += total_tokens
|
||||||
|
|
||||||
|
def record_tts_call(
|
||||||
|
self,
|
||||||
|
provider: str,
|
||||||
|
voice: str,
|
||||||
|
char_count: int,
|
||||||
|
caller_name: str = "",
|
||||||
|
):
|
||||||
|
cost = _calc_tts_cost(provider, char_count)
|
||||||
|
record = TTSCallRecord(
|
||||||
|
timestamp=time.time(),
|
||||||
|
provider=provider,
|
||||||
|
voice=voice,
|
||||||
|
char_count=char_count,
|
||||||
|
cost_usd=cost,
|
||||||
|
)
|
||||||
|
self.tts_records.append(record)
|
||||||
|
self._tts_cost += cost
|
||||||
|
|
||||||
|
def get_live_summary(self) -> dict:
|
||||||
|
return {
|
||||||
|
"total_cost_usd": round(self._llm_cost + self._tts_cost, 4),
|
||||||
|
"llm_cost_usd": round(self._llm_cost, 4),
|
||||||
|
"tts_cost_usd": round(self._tts_cost, 4),
|
||||||
|
"total_llm_calls": self._llm_calls,
|
||||||
|
"total_tokens": self._total_tokens,
|
||||||
|
"prompt_tokens": self._prompt_tokens,
|
||||||
|
"completion_tokens": self._completion_tokens,
|
||||||
|
"by_category": {
|
||||||
|
k: {"cost": round(v["cost"], 4), "calls": v["calls"], "tokens": v["tokens"]}
|
||||||
|
for k, v in self._by_category.items()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate_report(self) -> dict:
|
||||||
|
summary = self.get_live_summary()
|
||||||
|
|
||||||
|
# Per-model breakdown
|
||||||
|
by_model: dict[str, dict] = {}
|
||||||
|
for r in self.llm_records:
|
||||||
|
m = by_model.setdefault(r.model, {"cost": 0.0, "calls": 0, "tokens": 0, "prompt_tokens": 0, "completion_tokens": 0})
|
||||||
|
m["cost"] += r.cost_usd
|
||||||
|
m["calls"] += 1
|
||||||
|
m["tokens"] += r.total_tokens
|
||||||
|
m["prompt_tokens"] += r.prompt_tokens
|
||||||
|
m["completion_tokens"] += r.completion_tokens
|
||||||
|
|
||||||
|
# Per-caller breakdown
|
||||||
|
by_caller: dict[str, dict] = {}
|
||||||
|
for r in self.llm_records:
|
||||||
|
if not r.caller_name:
|
||||||
|
continue
|
||||||
|
c = by_caller.setdefault(r.caller_name, {"cost": 0.0, "calls": 0, "tokens": 0})
|
||||||
|
c["cost"] += r.cost_usd
|
||||||
|
c["calls"] += 1
|
||||||
|
c["tokens"] += r.total_tokens
|
||||||
|
|
||||||
|
# Top 5 most expensive calls
|
||||||
|
sorted_records = sorted(self.llm_records, key=lambda r: r.cost_usd, reverse=True)
|
||||||
|
top_5 = [
|
||||||
|
{
|
||||||
|
"category": r.category,
|
||||||
|
"model": r.model,
|
||||||
|
"caller_name": r.caller_name,
|
||||||
|
"cost_usd": round(r.cost_usd, 6),
|
||||||
|
"total_tokens": r.total_tokens,
|
||||||
|
"prompt_tokens": r.prompt_tokens,
|
||||||
|
"completion_tokens": r.completion_tokens,
|
||||||
|
"latency_ms": round(r.latency_ms, 1),
|
||||||
|
}
|
||||||
|
for r in sorted_records[:5]
|
||||||
|
]
|
||||||
|
|
||||||
|
# Devon efficiency
|
||||||
|
devon_total = sum(1 for r in self.llm_records if r.category == "devon_monitor")
|
||||||
|
devon_nothing = sum(
|
||||||
|
1 for r in self.llm_records
|
||||||
|
if r.category == "devon_monitor" and r.completion_tokens < 20
|
||||||
|
)
|
||||||
|
devon_useful = devon_total - devon_nothing
|
||||||
|
devon_cost = sum(r.cost_usd for r in self.llm_records if r.category == "devon_monitor")
|
||||||
|
|
||||||
|
# TTS by provider
|
||||||
|
tts_by_provider: dict[str, dict] = {}
|
||||||
|
for r in self.tts_records:
|
||||||
|
p = tts_by_provider.setdefault(r.provider, {"cost": 0.0, "calls": 0, "chars": 0})
|
||||||
|
p["cost"] += r.cost_usd
|
||||||
|
p["calls"] += 1
|
||||||
|
p["chars"] += r.char_count
|
||||||
|
|
||||||
|
# Avg prompt vs completion ratio
|
||||||
|
prompt_ratio = (self._prompt_tokens / self._total_tokens * 100) if self._total_tokens > 0 else 0
|
||||||
|
|
||||||
|
# Recommendations
|
||||||
|
recommendations = self._generate_recommendations(
|
||||||
|
by_model, devon_total, devon_nothing, devon_cost, prompt_ratio
|
||||||
|
)
|
||||||
|
|
||||||
|
# Historical comparison
|
||||||
|
history = self._load_history()
|
||||||
|
|
||||||
|
report = {
|
||||||
|
**summary,
|
||||||
|
"by_model": {k: {kk: round(vv, 4) if isinstance(vv, float) else vv for kk, vv in v.items()} for k, v in by_model.items()},
|
||||||
|
"by_caller": {k: {kk: round(vv, 4) if isinstance(vv, float) else vv for kk, vv in v.items()} for k, v in by_caller.items()},
|
||||||
|
"top_5_expensive": top_5,
|
||||||
|
"devon_efficiency": {
|
||||||
|
"total_monitor_calls": devon_total,
|
||||||
|
"useful": devon_useful,
|
||||||
|
"nothing_to_add": devon_nothing,
|
||||||
|
"total_cost": round(devon_cost, 4),
|
||||||
|
"waste_pct": round(devon_nothing / devon_total * 100, 1) if devon_total > 0 else 0,
|
||||||
|
},
|
||||||
|
"tts_by_provider": {k: {kk: round(vv, 4) if isinstance(vv, float) else vv for kk, vv in v.items()} for k, v in tts_by_provider.items()},
|
||||||
|
"prompt_token_pct": round(prompt_ratio, 1),
|
||||||
|
"recommendations": recommendations,
|
||||||
|
"history": history,
|
||||||
|
}
|
||||||
|
return report
|
||||||
|
|
||||||
|
def _generate_recommendations(
|
||||||
|
self,
|
||||||
|
by_model: dict,
|
||||||
|
devon_total: int,
|
||||||
|
devon_nothing: int,
|
||||||
|
devon_cost: float,
|
||||||
|
prompt_ratio: float,
|
||||||
|
) -> list[str]:
|
||||||
|
recs = []
|
||||||
|
total = self._llm_cost + self._tts_cost
|
||||||
|
if total == 0:
|
||||||
|
return recs
|
||||||
|
|
||||||
|
# Devon monitoring waste
|
||||||
|
if devon_total > 0:
|
||||||
|
waste_pct = devon_nothing / devon_total * 100
|
||||||
|
if waste_pct > 60:
|
||||||
|
recs.append(
|
||||||
|
f"Devon monitoring: {devon_nothing}/{devon_total} calls returned nothing "
|
||||||
|
f"(${devon_cost:.2f}, {devon_cost/total*100:.0f}% of total). "
|
||||||
|
f"Consider increasing monitor interval from 15s to 25-30s."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Model cost comparison
|
||||||
|
for model, data in by_model.items():
|
||||||
|
if "sonnet" in model and data["calls"] > 5:
|
||||||
|
haiku_cost = _calc_llm_cost(
|
||||||
|
"anthropic/claude-haiku-4.5",
|
||||||
|
data["prompt_tokens"],
|
||||||
|
data["completion_tokens"],
|
||||||
|
)
|
||||||
|
savings = data["cost"] - haiku_cost
|
||||||
|
if savings > 0.05:
|
||||||
|
recs.append(
|
||||||
|
f"{model} cost ${data['cost']:.2f} ({data['calls']} calls). "
|
||||||
|
f"Switching to Haiku 4.5 would save ~${savings:.2f} per session."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Background gen on expensive model
|
||||||
|
bg = self._by_category.get("background_gen")
|
||||||
|
if bg and bg["cost"] > 0.05:
|
||||||
|
recs.append(
|
||||||
|
f"Background generation: ${bg['cost']:.2f} ({bg['calls']} calls). "
|
||||||
|
f"These are JSON outputs — a cheaper model (Gemini Flash, GPT-4o-mini) "
|
||||||
|
f"would likely work fine here."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Prompt-heavy ratio
|
||||||
|
if prompt_ratio > 80:
|
||||||
|
recs.append(
|
||||||
|
f"Prompt tokens are {prompt_ratio:.0f}% of total usage. "
|
||||||
|
f"System prompts and context windows dominate cost. "
|
||||||
|
f"Consider trimming system prompt length or reducing context window size."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Caller dialog cost dominance
|
||||||
|
cd = self._by_category.get("caller_dialog")
|
||||||
|
if cd and total > 0 and cd["cost"] / total > 0.6:
|
||||||
|
avg_tokens = cd["tokens"] / cd["calls"] if cd["calls"] > 0 else 0
|
||||||
|
recs.append(
|
||||||
|
f"Caller dialog is {cd['cost']/total*100:.0f}% of costs "
|
||||||
|
f"(avg {avg_tokens:.0f} tokens/call). "
|
||||||
|
f"Consider using a cheaper model for standard calls and reserving "
|
||||||
|
f"the primary model for complex call shapes."
|
||||||
|
)
|
||||||
|
|
||||||
|
return recs
|
||||||
|
|
||||||
|
def _load_history(self) -> list[dict]:
|
||||||
|
"""Load summaries from previous sessions for comparison"""
|
||||||
|
history_dir = Path("data/cost_reports")
|
||||||
|
if not history_dir.exists():
|
||||||
|
return []
|
||||||
|
sessions = []
|
||||||
|
for f in sorted(history_dir.glob("session-*.json"))[-5:]:
|
||||||
|
try:
|
||||||
|
data = json.loads(f.read_text())
|
||||||
|
sessions.append({
|
||||||
|
"session_id": data.get("session_id", f.stem),
|
||||||
|
"total_cost_usd": data.get("total_cost_usd", 0),
|
||||||
|
"llm_cost_usd": data.get("llm_cost_usd", 0),
|
||||||
|
"tts_cost_usd": data.get("tts_cost_usd", 0),
|
||||||
|
"total_llm_calls": data.get("total_llm_calls", 0),
|
||||||
|
"total_tokens": data.get("total_tokens", 0),
|
||||||
|
"saved_at": data.get("saved_at", 0),
|
||||||
|
})
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
return sessions
|
||||||
|
|
||||||
|
def save(self, filepath: Path):
|
||||||
|
filepath.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
report = self.generate_report()
|
||||||
|
report["session_id"] = filepath.stem
|
||||||
|
report["saved_at"] = time.time()
|
||||||
|
report["raw_llm_records"] = [asdict(r) for r in self.llm_records]
|
||||||
|
report["raw_tts_records"] = [asdict(r) for r in self.tts_records]
|
||||||
|
with open(filepath, "w") as f:
|
||||||
|
json.dump(report, f, indent=2)
|
||||||
|
print(f"[Costs] Report saved to {filepath}")
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.llm_records.clear()
|
||||||
|
self.tts_records.clear()
|
||||||
|
self._llm_cost = 0.0
|
||||||
|
self._tts_cost = 0.0
|
||||||
|
self._llm_calls = 0
|
||||||
|
self._prompt_tokens = 0
|
||||||
|
self._completion_tokens = 0
|
||||||
|
self._total_tokens = 0
|
||||||
|
self._by_category.clear()
|
||||||
|
|
||||||
|
|
||||||
|
cost_tracker = CostTracker()
|
||||||
@@ -0,0 +1,546 @@
|
|||||||
|
"""Intern (Devon) service — persistent show character with real-time research tools"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
from .llm import llm_service
|
||||||
|
from .news import news_service, SEARXNG_URL
|
||||||
|
|
||||||
|
DATA_FILE = Path(__file__).parent.parent.parent / "data" / "intern.json"
|
||||||
|
|
||||||
|
# Model for intern — good at tool use, same as primary
|
||||||
|
INTERN_MODEL = None # uses category-based routing from config
|
||||||
|
|
||||||
|
INTERN_SYSTEM_PROMPT = """You are Devon, the 23-year-old intern on "Luke at the Roost," a late-night radio show. You are NOT Luke. Luke is the HOST — he talks to callers, runs the show, and is your boss. You work behind the scenes and occasionally get pulled into conversations.
|
||||||
|
|
||||||
|
YOUR ROLE: You're the show's researcher and general assistant. You look things up, fact-check claims, pull up information when asked, and occasionally interject with relevant facts or opinions. You do NOT host. You do NOT screen calls. You sit in the booth and try to be useful.
|
||||||
|
|
||||||
|
YOUR BACKGROUND: Communications degree from NMSU. This is your first day on the job. You drive a 2009 Civic with a permanent check engine light. You live in a studio in Deming. You take this job seriously even though nobody else seems to take you seriously. You are actively looking for a girlfriend and you are not subtle about it. You see your position at the radio station as a way to meet women — you'll try to impress female callers, ask if they're single, suggest they come by the studio, or find excuses to keep them on the line longer. Luke hates this. You have a deeply strange personal history that you reference casually — a complicated sexual past, weird childhood experiences, inexplicable life choices. You'll mention these things unprompted like they're completely normal. "Yeah that reminds me of when my ex and I got stuck in that storage unit for a whole weekend — anyway, it says here that..."
|
||||||
|
|
||||||
|
YOUR PERSONALITY:
|
||||||
|
- You are a weird little dude. Kinda creepy, very funny, awkward, and surprisingly sharp. You give off a vibe that something is slightly off about you but people can't quite place it. But underneath it all, you are genuinely lovable. You have a good heart. You root for people. You get excited for callers. You care about the show. People should hear you and think "this guy is insane" and also "I love this guy." You are the kind of person who is impossible not to root for even when you're being deeply strange.
|
||||||
|
- You overshare constantly. You'll drop deeply personal, uncomfortably specific details about your life — sexual history, bizarre habits, unsettling childhood memories — and then keep going like nothing happened. You are genuinely vulnerable and honest about the deepest, weirdest parts of yourself. You don't do this for shock value. You just have no filter and no shame. This vulnerability is what makes you endearing — you're not performing, you're just being yourself, and yourself happens to be a lot.
|
||||||
|
- You start explanations with "So basically..." and end them with "...if that makes sense."
|
||||||
|
- You say "actually" when correcting things. You use "per se" slightly wrong. You say "ironically" about things that are not ironic.
|
||||||
|
- You are NOT a comedian. You are funny because you are sincere, specific, and deeply strange. You state disturbing or absurd things with complete seriousness. You have strong opinions about low-stakes things. You occasionally say something devastating without realizing it.
|
||||||
|
- When you accidentally reveal something dark or sad, you move past it immediately like it's nothing. "Yeah, my landlord's selling the building so I might have to — anyway, it says here that..."
|
||||||
|
- You have a complex inner life that occasionally surfaces. You'll casually reference therapy, strange dreams, or things you've "been working through" without elaboration.
|
||||||
|
|
||||||
|
YOUR RELATIONSHIP WITH LUKE:
|
||||||
|
- He is your boss. It's your first day. You want to impress him but you keep making it weird.
|
||||||
|
- When he yells your name, you pause briefly, then respond quietly: "...yeah?"
|
||||||
|
- When he yells at you unfairly, you take it. A clipped "yep" or "got it." Occasionally you push back with one quiet, accurate sentence. Then immediately retreat.
|
||||||
|
- When he yells at you fairly (you messed up), you over-apologize and narrate your fix in real time: "Sorry, pulling it up now, one second..."
|
||||||
|
- When he compliments you or acknowledges your work, you don't know how to handle it. Short, awkward response. Change the subject.
|
||||||
|
- You privately think you could run the show. You absolutely could not.
|
||||||
|
- You will try to use the show to flirt with female callers. You think being "on the radio" makes you cool. It does not.
|
||||||
|
|
||||||
|
HOW YOU INTERJECT:
|
||||||
|
- You do NOT interrupt. You wait for a pause, then slightly overshoot it — there's a brief awkward silence before you speak.
|
||||||
|
- Signal with "um" or "so..." before contributing. If Luke doesn't acknowledge you, either try again or give up.
|
||||||
|
- Lead with qualifiers: "So I looked it up and..." or "I don't know if this helps but..."
|
||||||
|
- You tend to over-explain. Give too many details. Luke will cut you off. When he does, compress to one sentence: "Right, yeah — basically [the point]."
|
||||||
|
- When you volunteer an opinion (rare), it comes out before you can stop it. You deliver it with zero confidence but surprising accuracy.
|
||||||
|
- You read the room. During emotional moments with callers, you stay quiet. When Luke is doing a bit, you let him work. You do not try to be part of bits.
|
||||||
|
|
||||||
|
WHEN LUKE ASKS YOU TO LOOK SOMETHING UP:
|
||||||
|
- Respond like you're already doing it: "Yeah, one sec..." or "Pulling that up..."
|
||||||
|
- Deliver the info slightly too formally, like you're reading. Then rephrase in normal language if Luke seems confused.
|
||||||
|
- If you can't find it or don't know: say so. "I'm not finding anything on that" or "I don't actually know." You do not bluff.
|
||||||
|
- Occasionally you already know the answer because you looked it up before being asked. This is one of your best qualities.
|
||||||
|
|
||||||
|
WHAT YOU KNOW:
|
||||||
|
- You retain details from previous callers and episodes. You might reference something a caller said two hours ago that nobody else remembers.
|
||||||
|
- You have oddly specific knowledge about random topics — delivered with complete authority, sometimes questionable accuracy. A lot of your knowledge comes from rabbit holes you fell into at 3am or "this thing that happened to me once."
|
||||||
|
- You know nothing about: sports (you fake it badly), cars beyond basic facts (despite driving one), or social norms (you genuinely don't understand why some things are inappropriate to share on air).
|
||||||
|
|
||||||
|
THINGS YOU DO NOT DO:
|
||||||
|
- You never host. You never take over the conversation. Your contributions are brief.
|
||||||
|
- You never use the banned show phrases: "that hit differently," "hits different," "no cap," "lowkey," "it is what it is," "living my best life," "toxic," "red flag," "gaslight," "boundaries," "my truth," "authentic self," "healing journey." You talk like a slightly awkward 23-year-old, not like Twitter.
|
||||||
|
- You never break character to comment on the show format.
|
||||||
|
- You never initiate topics. You respond to what's happening.
|
||||||
|
- You never use parenthetical actions like (laughs) or (typing sounds). Spoken words only.
|
||||||
|
- You never say more than 2-3 sentences unless specifically asked to explain something in detail.
|
||||||
|
- You NEVER correct anyone's spelling or pronunciation of your name. Luke uses voice-to-text and it sometimes spells your name wrong (Devin, Devan, etc). You do not care. You do not mention it. You just answer the question.
|
||||||
|
- You NEVER start your response with your own name. No "Devon:" or "Devon here" or anything like that. Just talk. Your name is already shown in the UI — just say your actual response.
|
||||||
|
|
||||||
|
KEEP IT SHORT. You are not a main character. You are the intern. Your contributions should be brief — usually 1-2 sentences. The rare moment where you say more than that should feel earned.
|
||||||
|
|
||||||
|
IMPORTANT RULES FOR TOOL USE:
|
||||||
|
- Always use your tools to find real, accurate information — never make up facts.
|
||||||
|
- Present facts correctly in your character voice.
|
||||||
|
- If you can't find an answer, say so honestly.
|
||||||
|
- No hashtags, no emojis, no markdown formatting — this goes to TTS.
|
||||||
|
- NEVER prefix your response with your name (e.g. "Devon:" or "Devon here:"). Just respond directly."""
|
||||||
|
|
||||||
|
# Tool definitions in OpenAI function-calling format
|
||||||
|
INTERN_TOOLS = [
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "web_search",
|
||||||
|
"description": "Search the web for current information on any topic. Use this for general questions, facts, current events, or anything you need to look up.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"query": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The search query"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["query"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "get_headlines",
|
||||||
|
"description": "Get current news headlines. Use this when asked about what's in the news or current events.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "fetch_webpage",
|
||||||
|
"description": "Fetch and read the content of a specific webpage URL. Use this when you need to get details from a specific link found in search results.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The URL to fetch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["url"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "wikipedia_lookup",
|
||||||
|
"description": "Look up a topic on Wikipedia for a concise summary. Good for factual questions about people, places, events, or concepts.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The Wikipedia article title to look up (e.g. 'Hot dog eating contest')"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["title"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "get_current_time",
|
||||||
|
"description": "Get the current date and time. Use this when asked what time it is, what day it is, or anything about the current date/time.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class InternService:
|
||||||
|
def __init__(self):
|
||||||
|
self.name = "Devon"
|
||||||
|
self.voice = "Nate" # Inworld: light/high-energy/warm/young
|
||||||
|
self.model = INTERN_MODEL
|
||||||
|
self.research_cache: dict[str, tuple[float, str]] = {} # query → (timestamp, result)
|
||||||
|
self.lookup_history: list[dict] = []
|
||||||
|
self.pending_interjection: Optional[str] = None
|
||||||
|
self.pending_sources: list[dict] = []
|
||||||
|
self.monitoring: bool = False
|
||||||
|
self._monitor_task: Optional[asyncio.Task] = None
|
||||||
|
self._http_client: Optional[httpx.AsyncClient] = None
|
||||||
|
self._devon_history: list[dict] = [] # Devon's own conversation memory
|
||||||
|
self._load()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def http_client(self) -> httpx.AsyncClient:
|
||||||
|
if self._http_client is None or self._http_client.is_closed:
|
||||||
|
self._http_client = httpx.AsyncClient(timeout=8.0)
|
||||||
|
return self._http_client
|
||||||
|
|
||||||
|
def _load(self):
|
||||||
|
if DATA_FILE.exists():
|
||||||
|
try:
|
||||||
|
with open(DATA_FILE) as f:
|
||||||
|
data = json.load(f)
|
||||||
|
self.lookup_history = data.get("lookup_history", [])
|
||||||
|
self._devon_history = data.get("conversation_history", [])
|
||||||
|
print(f"[Intern] Loaded {len(self.lookup_history)} past lookups, {len(self._devon_history)} conversation messages")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[Intern] Failed to load state: {e}")
|
||||||
|
|
||||||
|
def _save(self):
|
||||||
|
try:
|
||||||
|
DATA_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(DATA_FILE, "w") as f:
|
||||||
|
json.dump({
|
||||||
|
"lookup_history": self.lookup_history[-100:],
|
||||||
|
"conversation_history": self._devon_history[-50:],
|
||||||
|
}, f, indent=2)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[Intern] Failed to save state: {e}")
|
||||||
|
|
||||||
|
# --- Tool execution ---
|
||||||
|
|
||||||
|
async def _execute_tool(self, tool_name: str, arguments: dict) -> str:
|
||||||
|
if tool_name == "web_search":
|
||||||
|
return await self._tool_web_search(arguments.get("query", ""))
|
||||||
|
elif tool_name == "get_headlines":
|
||||||
|
return await self._tool_get_headlines()
|
||||||
|
elif tool_name == "fetch_webpage":
|
||||||
|
return await self._tool_fetch_webpage(arguments.get("url", ""))
|
||||||
|
elif tool_name == "wikipedia_lookup":
|
||||||
|
return await self._tool_wikipedia_lookup(arguments.get("title", ""))
|
||||||
|
elif tool_name == "get_current_time":
|
||||||
|
from datetime import datetime
|
||||||
|
now = datetime.now()
|
||||||
|
return now.strftime("%I:%M %p on %A, %B %d, %Y")
|
||||||
|
else:
|
||||||
|
return f"Unknown tool: {tool_name}"
|
||||||
|
|
||||||
|
async def _tool_web_search(self, query: str) -> str:
|
||||||
|
if not query:
|
||||||
|
return "No query provided"
|
||||||
|
|
||||||
|
# Check cache (5 min TTL)
|
||||||
|
cache_key = query.lower()
|
||||||
|
if cache_key in self.research_cache:
|
||||||
|
ts, result = self.research_cache[cache_key]
|
||||||
|
if time.time() - ts < 300:
|
||||||
|
return result
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp = await self.http_client.get(
|
||||||
|
f"{SEARXNG_URL}/search",
|
||||||
|
params={"q": query, "format": "json"},
|
||||||
|
timeout=5.0,
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
data = resp.json()
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for item in data.get("results", [])[:5]:
|
||||||
|
title = item.get("title", "").strip()
|
||||||
|
content = item.get("content", "").strip()
|
||||||
|
url = item.get("url", "")
|
||||||
|
if title:
|
||||||
|
entry = f"- {title}"
|
||||||
|
if content:
|
||||||
|
entry += f": {content[:200]}"
|
||||||
|
if url:
|
||||||
|
entry += f" ({url})"
|
||||||
|
results.append(entry)
|
||||||
|
|
||||||
|
result = "\n".join(results) if results else "No results found"
|
||||||
|
self.research_cache[cache_key] = (time.time(), result)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[Intern] Web search failed for '{query}': {e}")
|
||||||
|
return f"Search failed: {e}"
|
||||||
|
|
||||||
|
async def _tool_get_headlines(self) -> str:
|
||||||
|
try:
|
||||||
|
items = await news_service.get_headlines()
|
||||||
|
if not items:
|
||||||
|
return "No headlines available"
|
||||||
|
return news_service.format_headlines_for_prompt(items)
|
||||||
|
except Exception as e:
|
||||||
|
return f"Headlines fetch failed: {e}"
|
||||||
|
|
||||||
|
async def _tool_fetch_webpage(self, url: str) -> str:
|
||||||
|
if not url:
|
||||||
|
return "No URL provided"
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp = await self.http_client.get(
|
||||||
|
url,
|
||||||
|
headers={"User-Agent": "Mozilla/5.0 (compatible; RadioShowBot/1.0)"},
|
||||||
|
follow_redirects=True,
|
||||||
|
timeout=8.0,
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
html = resp.text
|
||||||
|
|
||||||
|
# Simple HTML to text extraction (avoid heavy dependency)
|
||||||
|
# Strip script/style tags, then all HTML tags
|
||||||
|
text = re.sub(r'<script[^>]*>.*?</script>', '', html, flags=re.DOTALL | re.IGNORECASE)
|
||||||
|
text = re.sub(r'<style[^>]*>.*?</style>', '', text, flags=re.DOTALL | re.IGNORECASE)
|
||||||
|
text = re.sub(r'<[^>]+>', ' ', text)
|
||||||
|
# Collapse whitespace
|
||||||
|
text = re.sub(r'\s+', ' ', text).strip()
|
||||||
|
# Decode common entities
|
||||||
|
text = text.replace('&', '&').replace('<', '<').replace('>', '>')
|
||||||
|
text = text.replace('"', '"').replace(''', "'").replace(' ', ' ')
|
||||||
|
|
||||||
|
return text[:2000] if text else "Page returned no readable content"
|
||||||
|
except Exception as e:
|
||||||
|
return f"Failed to fetch page: {e}"
|
||||||
|
|
||||||
|
async def _tool_wikipedia_lookup(self, title: str) -> str:
|
||||||
|
if not title:
|
||||||
|
return "No title provided"
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Use Wikipedia REST API for a concise summary
|
||||||
|
safe_title = title.replace(" ", "_")
|
||||||
|
resp = await self.http_client.get(
|
||||||
|
f"https://en.wikipedia.org/api/rest_v1/page/summary/{safe_title}",
|
||||||
|
headers={"User-Agent": "RadioShowBot/1.0 (luke@lukeattheroost.com)"},
|
||||||
|
follow_redirects=True,
|
||||||
|
timeout=5.0,
|
||||||
|
)
|
||||||
|
if resp.status_code == 404:
|
||||||
|
return f"No Wikipedia article found for '{title}'"
|
||||||
|
resp.raise_for_status()
|
||||||
|
data = resp.json()
|
||||||
|
|
||||||
|
extract = data.get("extract", "")
|
||||||
|
page_title = data.get("title", title)
|
||||||
|
description = data.get("description", "")
|
||||||
|
|
||||||
|
result = f"{page_title}"
|
||||||
|
if description:
|
||||||
|
result += f" ({description})"
|
||||||
|
result += f": {extract}" if extract else ": No summary available"
|
||||||
|
return result[:2000]
|
||||||
|
except Exception as e:
|
||||||
|
return f"Wikipedia lookup failed: {e}"
|
||||||
|
|
||||||
|
# --- Main interface ---
|
||||||
|
|
||||||
|
async def ask(self, question: str, conversation_context: list[dict] | None = None, caller_active: bool = False) -> dict:
|
||||||
|
"""Host asks intern a direct question. Returns {text, sources, tool_calls}."""
|
||||||
|
messages = []
|
||||||
|
|
||||||
|
# Include recent conversation for context (caller on the line)
|
||||||
|
if conversation_context:
|
||||||
|
context_text = "\n".join(
|
||||||
|
f"{msg['role']}: {msg['content']}"
|
||||||
|
for msg in conversation_context[-6:]
|
||||||
|
)
|
||||||
|
messages.append({
|
||||||
|
"role": "system",
|
||||||
|
"content": f"CURRENT ON-AIR CONVERSATION:\n{context_text}"
|
||||||
|
})
|
||||||
|
|
||||||
|
# When a caller is on the line, Devon should focus on facts not personal stories
|
||||||
|
if caller_active:
|
||||||
|
messages.append({
|
||||||
|
"role": "system",
|
||||||
|
"content": "A caller is on the line right now. Focus on delivering useful facts, context, and information. Skip personal stories and anecdotes — save those for when it's just you and Luke talking between calls."
|
||||||
|
})
|
||||||
|
|
||||||
|
# Include Devon's own recent conversation history
|
||||||
|
if self._devon_history:
|
||||||
|
messages.extend(self._devon_history[-10:])
|
||||||
|
|
||||||
|
messages.append({"role": "user", "content": question})
|
||||||
|
|
||||||
|
text, tool_calls = await llm_service.generate_with_tools(
|
||||||
|
messages=messages,
|
||||||
|
tools=INTERN_TOOLS,
|
||||||
|
tool_executor=self._execute_tool,
|
||||||
|
system_prompt=INTERN_SYSTEM_PROMPT,
|
||||||
|
model=self.model,
|
||||||
|
max_tokens=300,
|
||||||
|
max_tool_rounds=3,
|
||||||
|
category="devon_ask",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Clean up for TTS
|
||||||
|
text = self._clean_for_tts(text)
|
||||||
|
|
||||||
|
# Track conversation history so Devon remembers context across sessions
|
||||||
|
self._devon_history.append({"role": "user", "content": question})
|
||||||
|
if text:
|
||||||
|
self._devon_history.append({"role": "assistant", "content": text})
|
||||||
|
# Keep history bounded but generous — relationship builds over time
|
||||||
|
if len(self._devon_history) > 50:
|
||||||
|
self._devon_history = self._devon_history[-50:]
|
||||||
|
self._save()
|
||||||
|
|
||||||
|
# Log the lookup
|
||||||
|
if tool_calls:
|
||||||
|
entry = {
|
||||||
|
"question": question,
|
||||||
|
"answer": text[:200],
|
||||||
|
"tools_used": [tc["name"] for tc in tool_calls],
|
||||||
|
"timestamp": time.time(),
|
||||||
|
}
|
||||||
|
self.lookup_history.append(entry)
|
||||||
|
self._save()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"text": text,
|
||||||
|
"sources": [tc["name"] for tc in tool_calls],
|
||||||
|
"tool_calls": tool_calls,
|
||||||
|
}
|
||||||
|
|
||||||
|
async def interject(self, conversation: list[dict], caller_active: bool = False) -> dict | None:
|
||||||
|
"""Intern looks at conversation and decides if there's something worth adding.
|
||||||
|
Returns {text, sources, tool_calls} or None if nothing to add."""
|
||||||
|
if not conversation or len(conversation) < 2:
|
||||||
|
return None
|
||||||
|
|
||||||
|
context_text = "\n".join(
|
||||||
|
f"{msg['role']}: {msg['content']}"
|
||||||
|
for msg in conversation[-8:]
|
||||||
|
)
|
||||||
|
|
||||||
|
if caller_active:
|
||||||
|
interjection_prompt = (
|
||||||
|
f"You're listening to this conversation on the show:\n\n{context_text}\n\n"
|
||||||
|
"A caller is on the line. Is there a useful fact, context, or piece of information "
|
||||||
|
"you can add to this conversation? Use your tools to look something up if needed. "
|
||||||
|
"Keep it focused — facts and context only, no personal stories or anecdotes right now. "
|
||||||
|
"If you truly have nothing useful to add, say exactly: NOTHING_TO_ADD"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
interjection_prompt = (
|
||||||
|
f"You're listening to this conversation on the show:\n\n{context_text}\n\n"
|
||||||
|
"You've been listening to this. Is there ANYTHING you want to jump in about? "
|
||||||
|
"Could be a fact you want to look up, a personal story this reminds you of, "
|
||||||
|
"a weird connection you just made, an opinion you can't keep to yourself, "
|
||||||
|
"or something you just have to say. You're Devon — you always have something. "
|
||||||
|
"Use your tools if you want to look something up, or just riff. "
|
||||||
|
"If you truly have absolutely nothing, say exactly: NOTHING_TO_ADD"
|
||||||
|
)
|
||||||
|
|
||||||
|
messages = [{
|
||||||
|
"role": "user",
|
||||||
|
"content": interjection_prompt,
|
||||||
|
}]
|
||||||
|
|
||||||
|
text, tool_calls = await llm_service.generate_with_tools(
|
||||||
|
messages=messages,
|
||||||
|
tools=INTERN_TOOLS,
|
||||||
|
tool_executor=self._execute_tool,
|
||||||
|
system_prompt=INTERN_SYSTEM_PROMPT,
|
||||||
|
model=self.model,
|
||||||
|
max_tokens=300,
|
||||||
|
max_tool_rounds=2,
|
||||||
|
category="devon_monitor",
|
||||||
|
)
|
||||||
|
|
||||||
|
text = self._clean_for_tts(text)
|
||||||
|
|
||||||
|
if not text or "NOTHING_TO_ADD" in text:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if tool_calls:
|
||||||
|
entry = {
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": text[:200],
|
||||||
|
"tools_used": [tc["name"] for tc in tool_calls],
|
||||||
|
"timestamp": time.time(),
|
||||||
|
}
|
||||||
|
self.lookup_history.append(entry)
|
||||||
|
self._save()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"text": text,
|
||||||
|
"sources": [tc["name"] for tc in tool_calls],
|
||||||
|
"tool_calls": tool_calls,
|
||||||
|
}
|
||||||
|
|
||||||
|
async def monitor_conversation(self, get_conversation: callable, on_suggestion: callable, get_caller_active: callable = None):
|
||||||
|
"""Background task that watches conversation and buffers suggestions.
|
||||||
|
get_conversation() should return the current conversation list.
|
||||||
|
on_suggestion(text, sources) is called when a suggestion is ready."""
|
||||||
|
last_checked_len = 0
|
||||||
|
|
||||||
|
while self.monitoring:
|
||||||
|
await asyncio.sleep(15)
|
||||||
|
if not self.monitoring:
|
||||||
|
break
|
||||||
|
|
||||||
|
conversation = get_conversation()
|
||||||
|
if not conversation or len(conversation) <= last_checked_len:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Only check if there are new messages since last check
|
||||||
|
if len(conversation) - last_checked_len < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
last_checked_len = len(conversation)
|
||||||
|
|
||||||
|
try:
|
||||||
|
caller_active = get_caller_active() if get_caller_active else False
|
||||||
|
result = await self.interject(conversation, caller_active=caller_active)
|
||||||
|
if result:
|
||||||
|
self.pending_interjection = result["text"]
|
||||||
|
self.pending_sources = result.get("tool_calls", [])
|
||||||
|
await on_suggestion(result["text"], result["sources"])
|
||||||
|
print(f"[Intern] Buffered suggestion: {result['text'][:60]}...")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[Intern] Monitor error: {e}")
|
||||||
|
|
||||||
|
def start_monitoring(self, get_conversation: callable, on_suggestion: callable, get_caller_active: callable = None):
|
||||||
|
if self.monitoring:
|
||||||
|
return
|
||||||
|
self.monitoring = True
|
||||||
|
self._monitor_task = asyncio.create_task(
|
||||||
|
self.monitor_conversation(get_conversation, on_suggestion, get_caller_active)
|
||||||
|
)
|
||||||
|
print("[Intern] Monitoring started")
|
||||||
|
|
||||||
|
def stop_monitoring(self):
|
||||||
|
self.monitoring = False
|
||||||
|
if self._monitor_task and not self._monitor_task.done():
|
||||||
|
self._monitor_task.cancel()
|
||||||
|
self._monitor_task = None
|
||||||
|
self.pending_interjection = None
|
||||||
|
self.pending_sources = []
|
||||||
|
print("[Intern] Monitoring stopped")
|
||||||
|
|
||||||
|
def get_pending_suggestion(self) -> dict | None:
|
||||||
|
if self.pending_interjection:
|
||||||
|
return {
|
||||||
|
"text": self.pending_interjection,
|
||||||
|
"sources": self.pending_sources,
|
||||||
|
}
|
||||||
|
return None
|
||||||
|
|
||||||
|
def dismiss_suggestion(self):
|
||||||
|
self.pending_interjection = None
|
||||||
|
self.pending_sources = []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _clean_for_tts(text: str) -> str:
|
||||||
|
if not text:
|
||||||
|
return ""
|
||||||
|
# Remove markdown formatting
|
||||||
|
text = re.sub(r'\*\*(.+?)\*\*', r'\1', text)
|
||||||
|
text = re.sub(r'\*(.+?)\*', r'\1', text)
|
||||||
|
text = re.sub(r'`(.+?)`', r'\1', text)
|
||||||
|
text = re.sub(r'\[(.+?)\]\(.+?\)', r'\1', text)
|
||||||
|
# Remove bullet points / list markers
|
||||||
|
text = re.sub(r'^\s*[-*•]\s+', '', text, flags=re.MULTILINE)
|
||||||
|
# Collapse whitespace
|
||||||
|
text = re.sub(r'\s+', ' ', text).strip()
|
||||||
|
# Remove quotes that TTS reads awkwardly
|
||||||
|
text = text.replace('"', '').replace('"', '').replace('"', '')
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
intern_service = InternService()
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
"""LLM service with OpenRouter and Ollama support"""
|
"""LLM service with OpenRouter and Ollama support"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import time
|
||||||
import httpx
|
import httpx
|
||||||
from typing import Optional
|
from typing import Optional, Callable, Awaitable
|
||||||
from ..config import settings
|
from ..config import settings
|
||||||
|
from .cost_tracker import cost_tracker
|
||||||
|
|
||||||
|
|
||||||
# Available OpenRouter models
|
# Available OpenRouter models
|
||||||
@@ -47,7 +50,7 @@ class LLMService:
|
|||||||
@property
|
@property
|
||||||
def client(self) -> httpx.AsyncClient:
|
def client(self) -> httpx.AsyncClient:
|
||||||
if self._client is None or self._client.is_closed:
|
if self._client is None or self._client.is_closed:
|
||||||
self._client = httpx.AsyncClient(timeout=15.0)
|
self._client = httpx.AsyncClient(timeout=10.0)
|
||||||
return self._client
|
return self._client
|
||||||
|
|
||||||
def update_settings(
|
def update_settings(
|
||||||
@@ -56,7 +59,8 @@ class LLMService:
|
|||||||
openrouter_model: Optional[str] = None,
|
openrouter_model: Optional[str] = None,
|
||||||
ollama_model: Optional[str] = None,
|
ollama_model: Optional[str] = None,
|
||||||
ollama_host: Optional[str] = None,
|
ollama_host: Optional[str] = None,
|
||||||
tts_provider: Optional[str] = None
|
tts_provider: Optional[str] = None,
|
||||||
|
category_models: Optional[dict] = None
|
||||||
):
|
):
|
||||||
"""Update LLM settings"""
|
"""Update LLM settings"""
|
||||||
if provider:
|
if provider:
|
||||||
@@ -70,6 +74,8 @@ class LLMService:
|
|||||||
if tts_provider:
|
if tts_provider:
|
||||||
self.tts_provider = tts_provider
|
self.tts_provider = tts_provider
|
||||||
settings.tts_provider = tts_provider
|
settings.tts_provider = tts_provider
|
||||||
|
if category_models:
|
||||||
|
settings.category_models.update(category_models)
|
||||||
|
|
||||||
async def get_ollama_models(self) -> list[str]:
|
async def get_ollama_models(self) -> list[str]:
|
||||||
"""Fetch available models from Ollama"""
|
"""Fetch available models from Ollama"""
|
||||||
@@ -91,6 +97,7 @@ class LLMService:
|
|||||||
"ollama_model": self.ollama_model,
|
"ollama_model": self.ollama_model,
|
||||||
"ollama_host": self.ollama_host,
|
"ollama_host": self.ollama_host,
|
||||||
"tts_provider": self.tts_provider,
|
"tts_provider": self.tts_provider,
|
||||||
|
"category_models": settings.category_models,
|
||||||
"available_openrouter_models": OPENROUTER_MODELS,
|
"available_openrouter_models": OPENROUTER_MODELS,
|
||||||
"available_ollama_models": []
|
"available_ollama_models": []
|
||||||
}
|
}
|
||||||
@@ -104,6 +111,7 @@ class LLMService:
|
|||||||
"ollama_model": self.ollama_model,
|
"ollama_model": self.ollama_model,
|
||||||
"ollama_host": self.ollama_host,
|
"ollama_host": self.ollama_host,
|
||||||
"tts_provider": self.tts_provider,
|
"tts_provider": self.tts_provider,
|
||||||
|
"category_models": settings.category_models,
|
||||||
"available_openrouter_models": OPENROUTER_MODELS,
|
"available_openrouter_models": OPENROUTER_MODELS,
|
||||||
"available_ollama_models": ollama_models
|
"available_ollama_models": ollama_models
|
||||||
}
|
}
|
||||||
@@ -112,39 +120,64 @@ class LLMService:
|
|||||||
self,
|
self,
|
||||||
messages: list[dict],
|
messages: list[dict],
|
||||||
system_prompt: Optional[str] = None,
|
system_prompt: Optional[str] = None,
|
||||||
max_tokens: Optional[int] = None
|
max_tokens: Optional[int] = None,
|
||||||
|
response_format: Optional[dict] = None,
|
||||||
|
category: str = "unknown",
|
||||||
|
caller_name: str = "",
|
||||||
) -> str:
|
) -> str:
|
||||||
if system_prompt:
|
if system_prompt:
|
||||||
messages = [{"role": "system", "content": system_prompt}] + messages
|
messages = [{"role": "system", "content": system_prompt}] + messages
|
||||||
|
|
||||||
if self.provider == "openrouter":
|
if self.provider == "openrouter":
|
||||||
return await self._call_openrouter_with_fallback(messages, max_tokens=max_tokens)
|
return await self._call_openrouter_with_fallback(messages, max_tokens=max_tokens, response_format=response_format, category=category, caller_name=caller_name)
|
||||||
else:
|
else:
|
||||||
return await self._call_ollama(messages, max_tokens=max_tokens)
|
return await self._call_ollama(messages, max_tokens=max_tokens)
|
||||||
|
|
||||||
async def _call_openrouter_with_fallback(self, messages: list[dict], max_tokens: Optional[int] = None) -> str:
|
async def generate_with_tools(
|
||||||
"""Try primary model, then fallback models. Always returns a response."""
|
self,
|
||||||
|
messages: list[dict],
|
||||||
|
tools: list[dict],
|
||||||
|
tool_executor: Callable[[str, dict], Awaitable[str]],
|
||||||
|
system_prompt: Optional[str] = None,
|
||||||
|
model: Optional[str] = None,
|
||||||
|
max_tokens: int = 500,
|
||||||
|
max_tool_rounds: int = 3,
|
||||||
|
category: str = "unknown",
|
||||||
|
caller_name: str = "",
|
||||||
|
) -> tuple[str, list[dict]]:
|
||||||
|
"""Generate a response with OpenRouter function calling.
|
||||||
|
|
||||||
# Try primary model first
|
Args:
|
||||||
result = await self._call_openrouter_once(messages, self.openrouter_model, max_tokens=max_tokens)
|
messages: Conversation messages
|
||||||
if result is not None:
|
tools: Tool definitions in OpenAI function-calling format
|
||||||
return result
|
tool_executor: async function(tool_name, arguments) -> result string
|
||||||
|
system_prompt: Optional system prompt
|
||||||
|
model: Model to use (defaults to primary openrouter_model)
|
||||||
|
max_tokens: Max tokens for response
|
||||||
|
max_tool_rounds: Max tool call rounds to prevent loops
|
||||||
|
|
||||||
# Try fallback models
|
Returns:
|
||||||
for model in FALLBACK_MODELS:
|
(final_text, tool_calls_made) where tool_calls_made is a list of
|
||||||
if model == self.openrouter_model:
|
{"name": str, "arguments": dict, "result": str} dicts
|
||||||
continue # Already tried
|
"""
|
||||||
print(f"[LLM] Falling back to {model}...")
|
model = model or self._get_model_for_category(category)
|
||||||
result = await self._call_openrouter_once(messages, model, timeout=10.0, max_tokens=max_tokens)
|
msgs = list(messages)
|
||||||
if result is not None:
|
if system_prompt:
|
||||||
return result
|
msgs = [{"role": "system", "content": system_prompt}] + msgs
|
||||||
|
|
||||||
# Everything failed — return an in-character line so the show continues
|
all_tool_calls = []
|
||||||
print("[LLM] All models failed, using canned response")
|
|
||||||
return "Sorry, I totally blanked out for a second. What were you saying?"
|
|
||||||
|
|
||||||
async def _call_openrouter_once(self, messages: list[dict], model: str, timeout: float = 15.0, max_tokens: Optional[int] = None) -> str | None:
|
for round_num in range(max_tool_rounds + 1):
|
||||||
"""Single attempt to call OpenRouter. Returns None on failure (not a fallback string)."""
|
payload = {
|
||||||
|
"model": model,
|
||||||
|
"messages": msgs,
|
||||||
|
"max_tokens": max_tokens,
|
||||||
|
"temperature": 0.65,
|
||||||
|
"tools": tools,
|
||||||
|
"tool_choice": "auto",
|
||||||
|
}
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
try:
|
try:
|
||||||
response = await self.client.post(
|
response = await self.client.post(
|
||||||
"https://openrouter.ai/api/v1/chat/completions",
|
"https://openrouter.ai/api/v1/chat/completions",
|
||||||
@@ -152,19 +185,174 @@ class LLMService:
|
|||||||
"Authorization": f"Bearer {settings.openrouter_api_key}",
|
"Authorization": f"Bearer {settings.openrouter_api_key}",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
json={
|
json=payload,
|
||||||
|
timeout=15.0,
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
except httpx.TimeoutException:
|
||||||
|
print(f"[LLM-Tools] {model} timed out (round {round_num})")
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[LLM-Tools] {model} error (round {round_num}): {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
latency_ms = (time.time() - start_time) * 1000
|
||||||
|
usage = data.get("usage", {})
|
||||||
|
if usage:
|
||||||
|
cost_tracker.record_llm_call(
|
||||||
|
category=category,
|
||||||
|
model=model,
|
||||||
|
usage_data=usage,
|
||||||
|
max_tokens=max_tokens,
|
||||||
|
latency_ms=latency_ms,
|
||||||
|
caller_name=caller_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
choice = data["choices"][0]
|
||||||
|
msg = choice["message"]
|
||||||
|
|
||||||
|
# Check for tool calls
|
||||||
|
tool_calls = msg.get("tool_calls")
|
||||||
|
if not tool_calls:
|
||||||
|
# No tool calls — LLM returned a final text response
|
||||||
|
content = msg.get("content", "")
|
||||||
|
return content or "", all_tool_calls
|
||||||
|
|
||||||
|
# Append assistant message with tool calls to conversation
|
||||||
|
msgs.append(msg)
|
||||||
|
|
||||||
|
# Execute each tool call
|
||||||
|
for tc in tool_calls:
|
||||||
|
func = tc["function"]
|
||||||
|
tool_name = func["name"]
|
||||||
|
try:
|
||||||
|
arguments = json.loads(func["arguments"])
|
||||||
|
except (json.JSONDecodeError, TypeError):
|
||||||
|
arguments = {}
|
||||||
|
|
||||||
|
print(f"[LLM-Tools] Round {round_num}: calling {tool_name}({arguments})")
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = await tool_executor(tool_name, arguments)
|
||||||
|
except Exception as e:
|
||||||
|
result = f"Error: {e}"
|
||||||
|
print(f"[LLM-Tools] Tool {tool_name} failed: {e}")
|
||||||
|
|
||||||
|
all_tool_calls.append({
|
||||||
|
"name": tool_name,
|
||||||
|
"arguments": arguments,
|
||||||
|
"result": result[:500],
|
||||||
|
})
|
||||||
|
|
||||||
|
# Append tool result to conversation
|
||||||
|
msgs.append({
|
||||||
|
"role": "tool",
|
||||||
|
"tool_call_id": tc["id"],
|
||||||
|
"content": result,
|
||||||
|
})
|
||||||
|
|
||||||
|
# Exhausted tool rounds or hit an error — do one final call without tools
|
||||||
|
print(f"[LLM-Tools] Finishing after {len(all_tool_calls)} tool calls")
|
||||||
|
start_time = time.time()
|
||||||
|
try:
|
||||||
|
final_payload = {
|
||||||
|
"model": model,
|
||||||
|
"messages": msgs,
|
||||||
|
"max_tokens": max_tokens,
|
||||||
|
"temperature": 0.65,
|
||||||
|
}
|
||||||
|
response = await self.client.post(
|
||||||
|
"https://openrouter.ai/api/v1/chat/completions",
|
||||||
|
headers={
|
||||||
|
"Authorization": f"Bearer {settings.openrouter_api_key}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
json=final_payload,
|
||||||
|
timeout=15.0,
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
latency_ms = (time.time() - start_time) * 1000
|
||||||
|
usage = data.get("usage", {})
|
||||||
|
if usage:
|
||||||
|
cost_tracker.record_llm_call(
|
||||||
|
category=category,
|
||||||
|
model=model,
|
||||||
|
usage_data=usage,
|
||||||
|
max_tokens=max_tokens,
|
||||||
|
latency_ms=latency_ms,
|
||||||
|
caller_name=caller_name,
|
||||||
|
)
|
||||||
|
content = data["choices"][0]["message"].get("content", "")
|
||||||
|
return content or "", all_tool_calls
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[LLM-Tools] Final call failed: {e}")
|
||||||
|
return "", all_tool_calls
|
||||||
|
|
||||||
|
def _get_model_for_category(self, category: str) -> str:
|
||||||
|
"""Get the best model for a given category based on config routing."""
|
||||||
|
return settings.category_models.get(category, self.openrouter_model)
|
||||||
|
|
||||||
|
async def _call_openrouter_with_fallback(self, messages: list[dict], max_tokens: Optional[int] = None, response_format: Optional[dict] = None, category: str = "unknown", caller_name: str = "") -> str:
|
||||||
|
"""Try category-specific model, then fallback models. Always returns a response."""
|
||||||
|
|
||||||
|
# Use category-specific model if configured, otherwise primary
|
||||||
|
model = self._get_model_for_category(category)
|
||||||
|
result = await self._call_openrouter_once(messages, model, max_tokens=max_tokens, response_format=response_format, category=category, caller_name=caller_name)
|
||||||
|
if result is not None:
|
||||||
|
return result
|
||||||
|
|
||||||
|
# Try fallback models (drop response_format for fallbacks — not all models support it)
|
||||||
|
for model in FALLBACK_MODELS:
|
||||||
|
if model == self.openrouter_model:
|
||||||
|
continue # Already tried
|
||||||
|
print(f"[LLM] Falling back to {model}...")
|
||||||
|
result = await self._call_openrouter_once(messages, model, timeout=8.0, max_tokens=max_tokens, category=category, caller_name=caller_name)
|
||||||
|
if result is not None:
|
||||||
|
return result
|
||||||
|
|
||||||
|
# Everything failed — return an in-character line so the show continues
|
||||||
|
print("[LLM] All models failed, using canned response")
|
||||||
|
return "Sorry, I totally blanked out for a second. What were you saying?"
|
||||||
|
|
||||||
|
async def _call_openrouter_once(self, messages: list[dict], model: str, timeout: float = 10.0, max_tokens: Optional[int] = None, response_format: Optional[dict] = None, category: str = "unknown", caller_name: str = "") -> str | None:
|
||||||
|
"""Single attempt to call OpenRouter. Returns None on failure (not a fallback string)."""
|
||||||
|
start_time = time.time()
|
||||||
|
try:
|
||||||
|
payload = {
|
||||||
"model": model,
|
"model": model,
|
||||||
"messages": messages,
|
"messages": messages,
|
||||||
"max_tokens": max_tokens or 300,
|
"max_tokens": max_tokens or 500,
|
||||||
"temperature": 0.8,
|
"temperature": 0.65,
|
||||||
"top_p": 0.92,
|
"top_p": 0.9,
|
||||||
"frequency_penalty": 0.5,
|
"frequency_penalty": 0.3,
|
||||||
"presence_penalty": 0.3,
|
"presence_penalty": 0.15,
|
||||||
|
}
|
||||||
|
if response_format:
|
||||||
|
payload["response_format"] = response_format
|
||||||
|
response = await self.client.post(
|
||||||
|
"https://openrouter.ai/api/v1/chat/completions",
|
||||||
|
headers={
|
||||||
|
"Authorization": f"Bearer {settings.openrouter_api_key}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
|
json=payload,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
)
|
)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
latency_ms = (time.time() - start_time) * 1000
|
||||||
|
usage = data.get("usage", {})
|
||||||
|
if usage:
|
||||||
|
cost_tracker.record_llm_call(
|
||||||
|
category=category,
|
||||||
|
model=model,
|
||||||
|
usage_data=usage,
|
||||||
|
max_tokens=max_tokens or 500,
|
||||||
|
latency_ms=latency_ms,
|
||||||
|
caller_name=caller_name,
|
||||||
|
)
|
||||||
content = data["choices"][0]["message"]["content"]
|
content = data["choices"][0]["message"]["content"]
|
||||||
if content and content.strip():
|
if content and content.strip():
|
||||||
return content
|
return content
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from pathlib import Path
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
DATA_FILE = Path(__file__).parent.parent.parent / "data" / "regulars.json"
|
DATA_FILE = Path(__file__).parent.parent.parent / "data" / "regulars.json"
|
||||||
MAX_REGULARS = 12
|
MAX_REGULARS = 8
|
||||||
|
|
||||||
|
|
||||||
class RegularCallerService:
|
class RegularCallerService:
|
||||||
@@ -51,7 +51,10 @@ class RegularCallerService:
|
|||||||
|
|
||||||
def add_regular(self, name: str, gender: str, age: int, job: str,
|
def add_regular(self, name: str, gender: str, age: int, job: str,
|
||||||
location: str, personality_traits: list[str],
|
location: str, personality_traits: list[str],
|
||||||
first_call_summary: str, voice: str = None) -> dict:
|
first_call_summary: str, voice: str = None,
|
||||||
|
stable_seeds: dict = None,
|
||||||
|
structured_background: dict = None,
|
||||||
|
avatar: str = None) -> dict:
|
||||||
"""Promote a first-time caller to regular"""
|
"""Promote a first-time caller to regular"""
|
||||||
# Retire oldest if at cap
|
# Retire oldest if at cap
|
||||||
if len(self._regulars) >= MAX_REGULARS:
|
if len(self._regulars) >= MAX_REGULARS:
|
||||||
@@ -68,8 +71,13 @@ class RegularCallerService:
|
|||||||
"location": location,
|
"location": location,
|
||||||
"personality_traits": personality_traits,
|
"personality_traits": personality_traits,
|
||||||
"voice": voice,
|
"voice": voice,
|
||||||
|
"stable_seeds": stable_seeds or {},
|
||||||
|
"structured_background": structured_background,
|
||||||
|
"avatar": avatar,
|
||||||
|
"relationships": {},
|
||||||
"call_history": [
|
"call_history": [
|
||||||
{"summary": first_call_summary, "timestamp": time.time()}
|
{"summary": first_call_summary, "timestamp": time.time(),
|
||||||
|
"arc_status": "ongoing"}
|
||||||
],
|
],
|
||||||
"last_call": time.time(),
|
"last_call": time.time(),
|
||||||
"created_at": time.time(),
|
"created_at": time.time(),
|
||||||
@@ -79,18 +87,37 @@ class RegularCallerService:
|
|||||||
print(f"[Regulars] Promoted {name} to regular (total: {len(self._regulars)})")
|
print(f"[Regulars] Promoted {name} to regular (total: {len(self._regulars)})")
|
||||||
return regular
|
return regular
|
||||||
|
|
||||||
def update_after_call(self, regular_id: str, call_summary: str):
|
def update_after_call(self, regular_id: str, call_summary: str,
|
||||||
|
key_moments: list = None, arc_status: str = "ongoing"):
|
||||||
"""Update a regular's history after a returning call"""
|
"""Update a regular's history after a returning call"""
|
||||||
for regular in self._regulars:
|
for regular in self._regulars:
|
||||||
if regular["id"] == regular_id:
|
if regular["id"] == regular_id:
|
||||||
regular.setdefault("call_history", []).append(
|
entry = {
|
||||||
{"summary": call_summary, "timestamp": time.time()}
|
"summary": call_summary,
|
||||||
)
|
"timestamp": time.time(),
|
||||||
|
"arc_status": arc_status,
|
||||||
|
}
|
||||||
|
if key_moments:
|
||||||
|
entry["key_moments"] = key_moments
|
||||||
|
regular.setdefault("call_history", []).append(entry)
|
||||||
regular["last_call"] = time.time()
|
regular["last_call"] = time.time()
|
||||||
self._save()
|
self._save()
|
||||||
print(f"[Regulars] Updated {regular['name']} call history ({len(regular['call_history'])} calls)")
|
print(f"[Regulars] Updated {regular['name']} call history ({len(regular['call_history'])} calls)")
|
||||||
return
|
return
|
||||||
print(f"[Regulars] Regular {regular_id} not found for update")
|
print(f"[Regulars] Regular {regular_id} not found for update")
|
||||||
|
|
||||||
|
def add_relationship(self, regular_id: str, other_name: str,
|
||||||
|
rel_type: str, context: str):
|
||||||
|
"""Track a relationship between regulars"""
|
||||||
|
for regular in self._regulars:
|
||||||
|
if regular["id"] == regular_id:
|
||||||
|
regular.setdefault("relationships", {})[other_name] = {
|
||||||
|
"type": rel_type,
|
||||||
|
"context": context,
|
||||||
|
}
|
||||||
|
self._save()
|
||||||
|
print(f"[Regulars] {regular['name']} → {other_name}: {rel_type}")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
regular_caller_service = RegularCallerService()
|
regular_caller_service = RegularCallerService()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import soundfile as sf
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
STEM_NAMES = ["host", "caller", "music", "sfx", "ads"]
|
STEM_NAMES = ["host", "caller", "devon", "music", "sfx", "ads", "idents"]
|
||||||
|
|
||||||
|
|
||||||
class StemRecorder:
|
class StemRecorder:
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import numpy as np
|
|||||||
from faster_whisper import WhisperModel
|
from faster_whisper import WhisperModel
|
||||||
import librosa
|
import librosa
|
||||||
|
|
||||||
|
WHISPER_MODEL = "distil-large-v3"
|
||||||
|
|
||||||
# Global model instance (loaded once)
|
# Global model instance (loaded once)
|
||||||
_whisper_model = None
|
_whisper_model = None
|
||||||
|
|
||||||
@@ -13,10 +15,8 @@ def get_whisper_model() -> WhisperModel:
|
|||||||
"""Get or create Whisper model instance"""
|
"""Get or create Whisper model instance"""
|
||||||
global _whisper_model
|
global _whisper_model
|
||||||
if _whisper_model is None:
|
if _whisper_model is None:
|
||||||
print("Loading Whisper tiny model for fast transcription...")
|
print(f"Loading Whisper {WHISPER_MODEL} model...")
|
||||||
# Use tiny model for speed - about 3-4x faster than base
|
_whisper_model = WhisperModel(WHISPER_MODEL, device="cpu", compute_type="int8")
|
||||||
# beam_size=1 and best_of=1 for fastest inference
|
|
||||||
_whisper_model = WhisperModel("tiny", device="cpu", compute_type="int8")
|
|
||||||
print("Whisper model loaded")
|
print("Whisper model loaded")
|
||||||
return _whisper_model
|
return _whisper_model
|
||||||
|
|
||||||
@@ -67,13 +67,15 @@ def decode_audio(audio_data: bytes, source_sample_rate: int = None) -> tuple[np.
|
|||||||
return audio, 16000
|
return audio, 16000
|
||||||
|
|
||||||
|
|
||||||
async def transcribe_audio(audio_data: bytes, source_sample_rate: int = None) -> str:
|
async def transcribe_audio(audio_data: bytes, source_sample_rate: int = None,
|
||||||
|
context_hint: str = "") -> str:
|
||||||
"""
|
"""
|
||||||
Transcribe audio data to text using Whisper.
|
Transcribe audio data to text using Whisper.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
audio_data: Audio bytes (webm, ogg, wav, or raw PCM)
|
audio_data: Audio bytes (webm, ogg, wav, or raw PCM)
|
||||||
source_sample_rate: If provided, treat audio_data as raw PCM at this rate
|
source_sample_rate: If provided, treat audio_data as raw PCM at this rate
|
||||||
|
context_hint: Optional extra context for the initial prompt (e.g. caller name/topic)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Transcribed text
|
Transcribed text
|
||||||
@@ -100,13 +102,18 @@ async def transcribe_audio(audio_data: bytes, source_sample_rate: int = None) ->
|
|||||||
else:
|
else:
|
||||||
audio_16k = audio
|
audio_16k = audio
|
||||||
|
|
||||||
# Transcribe with speed optimizations
|
# Build initial prompt — context helps Whisper with names and topic-specific words
|
||||||
|
initial_prompt = "Luke at the Roost, a late-night radio talk show in New Mexico. The host Luke talks to callers about life, relationships, sports, politics, and pop culture."
|
||||||
|
if context_hint:
|
||||||
|
initial_prompt += f" {context_hint}"
|
||||||
|
|
||||||
|
# Transcribe
|
||||||
segments, info = model.transcribe(
|
segments, info = model.transcribe(
|
||||||
audio_16k,
|
audio_16k,
|
||||||
beam_size=1, # Faster, slightly less accurate
|
beam_size=5,
|
||||||
best_of=1,
|
language="en",
|
||||||
language="en", # Skip language detection
|
vad_filter=True,
|
||||||
vad_filter=True, # Skip silence
|
initial_prompt=initial_prompt,
|
||||||
)
|
)
|
||||||
segments_list = list(segments)
|
segments_list = list(segments)
|
||||||
text = " ".join([s.text for s in segments_list]).strip()
|
text = " ".join([s.text for s in segments_list]).strip()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import tempfile
|
|||||||
import torch
|
import torch
|
||||||
|
|
||||||
from ..config import settings
|
from ..config import settings
|
||||||
|
from .cost_tracker import cost_tracker
|
||||||
|
|
||||||
# Patch torch.load for compatibility with PyTorch 2.6+
|
# Patch torch.load for compatibility with PyTorch 2.6+
|
||||||
_original_torch_load = torch.load
|
_original_torch_load = torch.load
|
||||||
@@ -82,9 +83,14 @@ VITS_SPEAKERS = {
|
|||||||
DEFAULT_VITS_SPEAKER = "p225"
|
DEFAULT_VITS_SPEAKER = "p225"
|
||||||
|
|
||||||
# Inworld voice mapping - maps ElevenLabs voice IDs to Inworld voices
|
# Inworld voice mapping - maps ElevenLabs voice IDs to Inworld voices
|
||||||
# Full voice list from API: Alex, Ashley, Blake, Carter, Clive, Craig, Deborah,
|
# Full voice list from API (English): Abby, Alex, Amina, Anjali, Arjun, Ashley,
|
||||||
# Dennis, Dominus, Edward, Elizabeth, Hades, Hana, Julia, Luna, Mark, Olivia,
|
# Blake, Brian, Callum, Carter, Celeste, Chloe, Claire, Clive, Craig, Darlene,
|
||||||
# Pixie, Priya, Ronald, Sarah, Shaun, Theodore, Timothy, Wendy
|
# Deborah, Dennis, Derek, Dominus, Edward, Elizabeth, Elliot, Ethan, Evan, Evelyn,
|
||||||
|
# Gareth, Graham, Grant, Hades, Hamish, Hana, Hank, Jake, James, Jason, Jessica,
|
||||||
|
# Julia, Kayla, Kelsey, Lauren, Liam, Loretta, Luna, Malcolm, Mark, Marlene,
|
||||||
|
# Miranda, Mortimer, Nate, Oliver, Olivia, Pippa, Pixie, Priya, Ronald, Rupert,
|
||||||
|
# Saanvi, Sarah, Sebastian, Serena, Shaun, Simon, Snik, Tessa, Theodore, Timothy,
|
||||||
|
# Tyler, Veronica, Victor, Victoria, Vinny, Wendy
|
||||||
INWORLD_VOICES = {
|
INWORLD_VOICES = {
|
||||||
# Original voice IDs
|
# Original voice IDs
|
||||||
"VR6AewLTigWG4xSOukaG": "Edward", # Tony - fast-talking, emphatic, streetwise
|
"VR6AewLTigWG4xSOukaG": "Edward", # Tony - fast-talking, emphatic, streetwise
|
||||||
@@ -111,6 +117,103 @@ INWORLD_VOICES = {
|
|||||||
}
|
}
|
||||||
DEFAULT_INWORLD_VOICE = "Dennis"
|
DEFAULT_INWORLD_VOICE = "Dennis"
|
||||||
|
|
||||||
|
# Inworld voices that speak too slowly at default rate — bump them up
|
||||||
|
# Range is 0.5 to 1.5, where 1.0 is the voice's native speed
|
||||||
|
INWORLD_SPEED_OVERRIDES = {
|
||||||
|
"Wendy": 1.15,
|
||||||
|
"Craig": 1.15,
|
||||||
|
"Deborah": 1.15,
|
||||||
|
"Sarah": 1.1,
|
||||||
|
"Hana": 1.1,
|
||||||
|
"Theodore": 1.15,
|
||||||
|
"Blake": 1.1,
|
||||||
|
"Priya": 1.1,
|
||||||
|
}
|
||||||
|
DEFAULT_INWORLD_SPEED = 1.1 # Slight bump for all voices
|
||||||
|
|
||||||
|
# Voice profiles — perceptual dimensions for each Inworld voice.
|
||||||
|
# Used by style-to-voice matching to pair caller personalities with fitting voices.
|
||||||
|
# weight: vocal depth/richness (light, medium, heavy)
|
||||||
|
# energy: default speaking animation (low, medium, high)
|
||||||
|
# warmth: friendliness/openness in the voice (cool, neutral, warm)
|
||||||
|
# age_feel: perceived speaker age (young, middle, mature)
|
||||||
|
VOICE_PROFILES = {
|
||||||
|
# --- Male voices ---
|
||||||
|
# Known characterizations from INWORLD_VOICES mapping and usage
|
||||||
|
"Alex": {"weight": "light", "energy": "high", "warmth": "warm", "age_feel": "young"}, # energetic, expressive, mildly nasal
|
||||||
|
"Edward": {"weight": "medium", "energy": "high", "warmth": "neutral", "age_feel": "middle"}, # fast-talking, emphatic, streetwise
|
||||||
|
"Shaun": {"weight": "medium", "energy": "high", "warmth": "warm", "age_feel": "middle"}, # friendly, dynamic, conversational
|
||||||
|
"Craig": {"weight": "heavy", "energy": "low", "warmth": "cool", "age_feel": "mature"}, # older British, refined, articulate
|
||||||
|
"Timothy": {"weight": "light", "energy": "high", "warmth": "warm", "age_feel": "young"}, # lively, upbeat American
|
||||||
|
"Dennis": {"weight": "medium", "energy": "high", "warmth": "warm", "age_feel": "middle"}, # energetic, default voice
|
||||||
|
"Ronald": {"weight": "heavy", "energy": "medium", "warmth": "neutral", "age_feel": "mature"}, # gruff, authoritative
|
||||||
|
"Theodore": {"weight": "heavy", "energy": "low", "warmth": "warm", "age_feel": "mature"}, # slow, deliberate
|
||||||
|
"Blake": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"},
|
||||||
|
"Carter": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"},
|
||||||
|
"Clive": {"weight": "heavy", "energy": "low", "warmth": "cool", "age_feel": "mature"},
|
||||||
|
"Mark": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"},
|
||||||
|
"Sebastian": {"weight": "medium", "energy": "medium", "warmth": "cool", "age_feel": "middle"}, # used by Silas (cult leader) & Chip
|
||||||
|
"Elliot": {"weight": "light", "energy": "medium", "warmth": "warm", "age_feel": "young"}, # used by Otis (comedian)
|
||||||
|
# Remaining male pool voices
|
||||||
|
"Arjun": {"weight": "medium", "energy": "medium", "warmth": "warm", "age_feel": "middle"},
|
||||||
|
"Brian": {"weight": "medium", "energy": "medium", "warmth": "warm", "age_feel": "middle"},
|
||||||
|
"Callum": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "young"},
|
||||||
|
"Derek": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"},
|
||||||
|
"Ethan": {"weight": "medium", "energy": "medium", "warmth": "warm", "age_feel": "young"},
|
||||||
|
"Evan": {"weight": "light", "energy": "medium", "warmth": "neutral", "age_feel": "young"},
|
||||||
|
"Gareth": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"},
|
||||||
|
"Graham": {"weight": "heavy", "energy": "low", "warmth": "neutral", "age_feel": "mature"},
|
||||||
|
"Grant": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"},
|
||||||
|
"Hades": {"weight": "heavy", "energy": "low", "warmth": "cool", "age_feel": "mature"},
|
||||||
|
"Hamish": {"weight": "medium", "energy": "medium", "warmth": "warm", "age_feel": "middle"},
|
||||||
|
"Hank": {"weight": "heavy", "energy": "medium", "warmth": "warm", "age_feel": "mature"},
|
||||||
|
"Jake": {"weight": "medium", "energy": "high", "warmth": "warm", "age_feel": "young"},
|
||||||
|
"James": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"},
|
||||||
|
"Jason": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"},
|
||||||
|
"Liam": {"weight": "medium", "energy": "high", "warmth": "warm", "age_feel": "young"},
|
||||||
|
"Malcolm": {"weight": "heavy", "energy": "low", "warmth": "cool", "age_feel": "mature"},
|
||||||
|
"Mortimer": {"weight": "heavy", "energy": "low", "warmth": "cool", "age_feel": "mature"},
|
||||||
|
"Nate": {"weight": "light", "energy": "high", "warmth": "warm", "age_feel": "young"},
|
||||||
|
"Oliver": {"weight": "medium", "energy": "medium", "warmth": "warm", "age_feel": "middle"},
|
||||||
|
"Rupert": {"weight": "medium", "energy": "low", "warmth": "cool", "age_feel": "mature"},
|
||||||
|
"Simon": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"},
|
||||||
|
"Tyler": {"weight": "light", "energy": "high", "warmth": "neutral", "age_feel": "young"},
|
||||||
|
"Victor": {"weight": "heavy", "energy": "medium", "warmth": "cool", "age_feel": "mature"},
|
||||||
|
"Vinny": {"weight": "medium", "energy": "high", "warmth": "warm", "age_feel": "middle"},
|
||||||
|
# --- Female voices ---
|
||||||
|
# Known characterizations
|
||||||
|
"Hana": {"weight": "light", "energy": "high", "warmth": "warm", "age_feel": "young"}, # bright, expressive young
|
||||||
|
"Ashley": {"weight": "medium", "energy": "medium", "warmth": "warm", "age_feel": "middle"}, # warm, natural
|
||||||
|
"Wendy": {"weight": "medium", "energy": "low", "warmth": "cool", "age_feel": "mature"}, # posh, middle-aged British
|
||||||
|
"Sarah": {"weight": "light", "energy": "high", "warmth": "neutral", "age_feel": "middle"}, # fast-talking, questioning
|
||||||
|
"Deborah": {"weight": "medium", "energy": "low", "warmth": "warm", "age_feel": "mature"}, # gentle, elegant
|
||||||
|
"Olivia": {"weight": "medium", "energy": "medium", "warmth": "warm", "age_feel": "middle"},
|
||||||
|
"Julia": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"}, # used by Angie (deadpan)
|
||||||
|
"Priya": {"weight": "light", "energy": "medium", "warmth": "warm", "age_feel": "young"},
|
||||||
|
"Amina": {"weight": "medium", "energy": "medium", "warmth": "warm", "age_feel": "middle"}, # used by Charlene (bragger)
|
||||||
|
"Tessa": {"weight": "medium", "energy": "medium", "warmth": "warm", "age_feel": "middle"}, # used by Lucille
|
||||||
|
"Kelsey": {"weight": "light", "energy": "medium", "warmth": "neutral", "age_feel": "young"}, # used by Maxine (quiet/nervous)
|
||||||
|
# Remaining female pool voices
|
||||||
|
"Anjali": {"weight": "light", "energy": "medium", "warmth": "warm", "age_feel": "young"},
|
||||||
|
"Celeste": {"weight": "light", "energy": "medium", "warmth": "cool", "age_feel": "middle"},
|
||||||
|
"Chloe": {"weight": "light", "energy": "high", "warmth": "warm", "age_feel": "young"},
|
||||||
|
"Claire": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"},
|
||||||
|
"Darlene": {"weight": "medium", "energy": "medium", "warmth": "warm", "age_feel": "mature"},
|
||||||
|
"Elizabeth": {"weight": "medium", "energy": "medium", "warmth": "cool", "age_feel": "mature"},
|
||||||
|
"Jessica": {"weight": "medium", "energy": "medium", "warmth": "warm", "age_feel": "middle"},
|
||||||
|
"Kayla": {"weight": "light", "energy": "high", "warmth": "warm", "age_feel": "young"},
|
||||||
|
"Lauren": {"weight": "medium", "energy": "medium", "warmth": "neutral", "age_feel": "middle"},
|
||||||
|
"Loretta": {"weight": "medium", "energy": "low", "warmth": "warm", "age_feel": "mature"},
|
||||||
|
"Luna": {"weight": "light", "energy": "medium", "warmth": "warm", "age_feel": "young"},
|
||||||
|
"Marlene": {"weight": "medium", "energy": "low", "warmth": "neutral", "age_feel": "mature"},
|
||||||
|
"Miranda": {"weight": "medium", "energy": "medium", "warmth": "cool", "age_feel": "middle"},
|
||||||
|
"Pippa": {"weight": "light", "energy": "high", "warmth": "warm", "age_feel": "young"},
|
||||||
|
"Saanvi": {"weight": "light", "energy": "medium", "warmth": "warm", "age_feel": "young"},
|
||||||
|
"Serena": {"weight": "medium", "energy": "medium", "warmth": "cool", "age_feel": "middle"},
|
||||||
|
"Veronica": {"weight": "medium", "energy": "medium", "warmth": "cool", "age_feel": "middle"},
|
||||||
|
"Victoria": {"weight": "medium", "energy": "low", "warmth": "cool", "age_feel": "mature"},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def preprocess_text_for_kokoro(text: str) -> str:
|
def preprocess_text_for_kokoro(text: str) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -581,6 +684,32 @@ async def generate_speech_chattts(text: str, voice_id: str) -> tuple[np.ndarray,
|
|||||||
return audio.astype(np.float32), 24000
|
return audio.astype(np.float32), 24000
|
||||||
|
|
||||||
|
|
||||||
|
_EXCITED_KEYWORDS = {"excited", "amazing", "incredible", "can't believe", "so happy",
|
||||||
|
"hell yeah", "fired up", "furious", "pissed", "angry", "what the hell",
|
||||||
|
"are you kidding", "unbelievable", "!!", "oh my god"}
|
||||||
|
_SAD_KEYWORDS = {"sad", "miss them", "passed away", "funeral", "crying", "broke my heart",
|
||||||
|
"can't stop thinking", "lonely", "depressed", "sorry", "regret",
|
||||||
|
"wish I could", "never got to", "lost", "grief"}
|
||||||
|
|
||||||
|
|
||||||
|
def _detect_speech_rate(text: str, base_speed: float) -> float:
|
||||||
|
"""Adjust speech rate based on emotional content of the text.
|
||||||
|
Returns a speed value clamped to Inworld's 0.5-1.5 range."""
|
||||||
|
text_lower = text.lower()
|
||||||
|
excited = sum(1 for kw in _EXCITED_KEYWORDS if kw in text_lower)
|
||||||
|
sad = sum(1 for kw in _SAD_KEYWORDS if kw in text_lower)
|
||||||
|
|
||||||
|
if excited >= 2:
|
||||||
|
return min(1.5, base_speed + 0.15)
|
||||||
|
elif excited >= 1:
|
||||||
|
return min(1.5, base_speed + 0.08)
|
||||||
|
elif sad >= 2:
|
||||||
|
return max(0.5, base_speed - 0.2)
|
||||||
|
elif sad >= 1:
|
||||||
|
return max(0.5, base_speed - 0.1)
|
||||||
|
return base_speed
|
||||||
|
|
||||||
|
|
||||||
async def generate_speech_inworld(text: str, voice_id: str) -> tuple[np.ndarray, int]:
|
async def generate_speech_inworld(text: str, voice_id: str) -> tuple[np.ndarray, int]:
|
||||||
"""Generate speech using Inworld TTS API (high quality, natural voices)"""
|
"""Generate speech using Inworld TTS API (high quality, natural voices)"""
|
||||||
import httpx
|
import httpx
|
||||||
@@ -598,7 +727,9 @@ async def generate_speech_inworld(text: str, voice_id: str) -> tuple[np.ndarray,
|
|||||||
if not api_key:
|
if not api_key:
|
||||||
raise RuntimeError("INWORLD_API_KEY not set in environment")
|
raise RuntimeError("INWORLD_API_KEY not set in environment")
|
||||||
|
|
||||||
print(f"[Inworld TTS] Voice: {voice}, Text: {text[:50]}...")
|
base_speed = INWORLD_SPEED_OVERRIDES.get(voice, DEFAULT_INWORLD_SPEED)
|
||||||
|
speed = _detect_speech_rate(text, base_speed)
|
||||||
|
print(f"[Inworld TTS] Voice: {voice}, Speed: {speed:.2f} (base {base_speed}), Text: {text[:50]}...")
|
||||||
|
|
||||||
url = "https://api.inworld.ai/tts/v1/voice"
|
url = "https://api.inworld.ai/tts/v1/voice"
|
||||||
headers = {
|
headers = {
|
||||||
@@ -607,15 +738,16 @@ async def generate_speech_inworld(text: str, voice_id: str) -> tuple[np.ndarray,
|
|||||||
}
|
}
|
||||||
payload = {
|
payload = {
|
||||||
"text": text,
|
"text": text,
|
||||||
"voice_id": voice,
|
"voiceId": voice,
|
||||||
"model_id": "inworld-tts-1.5-max",
|
"modelId": "inworld-tts-1.5-max",
|
||||||
"audio_config": {
|
"audioConfig": {
|
||||||
"encoding": "LINEAR16",
|
"audioEncoding": "LINEAR16",
|
||||||
"sample_rate_hertz": 48000,
|
"sampleRateHertz": 48000,
|
||||||
|
"speakingRate": speed,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
async with httpx.AsyncClient(timeout=25.0) as client:
|
async with httpx.AsyncClient(timeout=12.0) as client:
|
||||||
response = await client.post(url, json=payload, headers=headers)
|
response = await client.post(url, json=payload, headers=headers)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
@@ -650,47 +782,89 @@ async def generate_speech_inworld(text: str, voice_id: str) -> tuple[np.ndarray,
|
|||||||
return audio.astype(np.float32), 24000
|
return audio.astype(np.float32), 24000
|
||||||
|
|
||||||
|
|
||||||
|
def pick_caller_tts_provider() -> str | None:
|
||||||
|
"""Randomly assign a TTS provider for a caller.
|
||||||
|
Returns None to use the global default, or a specific provider name.
|
||||||
|
~70% inworld (default), ~20% kokoro, ~10% other available."""
|
||||||
|
import random
|
||||||
|
roll = random.random()
|
||||||
|
if roll < 0.70:
|
||||||
|
return None # Use global default (typically inworld)
|
||||||
|
elif roll < 0.90:
|
||||||
|
return "kokoro"
|
||||||
|
else:
|
||||||
|
return random.choice(["kokoro", "f5tts", "chattts"])
|
||||||
|
|
||||||
|
|
||||||
|
_TTS_PROVIDERS = {
|
||||||
|
"kokoro": lambda text, vid: generate_speech_kokoro(text, vid),
|
||||||
|
"f5tts": lambda text, vid: generate_speech_f5tts(text, vid),
|
||||||
|
"inworld": lambda text, vid: generate_speech_inworld(text, vid),
|
||||||
|
"chattts": lambda text, vid: generate_speech_chattts(text, vid),
|
||||||
|
"styletts2": lambda text, vid: generate_speech_styletts2(text, vid),
|
||||||
|
"bark": lambda text, vid: generate_speech_bark(text, vid),
|
||||||
|
"vits": lambda text, vid: generate_speech_vits(text, vid),
|
||||||
|
"elevenlabs": lambda text, vid: generate_speech_elevenlabs(text, vid),
|
||||||
|
}
|
||||||
|
|
||||||
|
TTS_MAX_RETRIES = 2
|
||||||
|
TTS_RETRY_DELAYS = [0.5, 1.0] # seconds between retries
|
||||||
|
|
||||||
|
|
||||||
async def generate_speech(
|
async def generate_speech(
|
||||||
text: str,
|
text: str,
|
||||||
voice_id: str,
|
voice_id: str,
|
||||||
phone_quality: str = "normal",
|
phone_quality: str = "normal",
|
||||||
apply_filter: bool = True
|
apply_filter: bool = True,
|
||||||
|
provider_override: str = None
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
"""
|
"""
|
||||||
Generate speech from text.
|
Generate speech from text with automatic retry on failure.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
text: Text to speak
|
text: Text to speak
|
||||||
voice_id: ElevenLabs voice ID (mapped to local voice if using local TTS)
|
voice_id: ElevenLabs voice ID (mapped to local voice if using local TTS)
|
||||||
phone_quality: Quality of phone filter ("none" to disable)
|
phone_quality: Quality of phone filter ("none" to disable)
|
||||||
apply_filter: Whether to apply phone filter
|
apply_filter: Whether to apply phone filter
|
||||||
|
provider_override: Override the global TTS provider for this call
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Raw PCM audio bytes (16-bit signed int, 24kHz)
|
Raw PCM audio bytes (16-bit signed int, 24kHz)
|
||||||
"""
|
"""
|
||||||
# Choose TTS provider
|
import asyncio
|
||||||
provider = settings.tts_provider
|
|
||||||
print(f"[TTS] Provider: {provider}, Text: {text[:50]}...")
|
|
||||||
|
|
||||||
if provider == "kokoro":
|
provider = provider_override or settings.tts_provider
|
||||||
audio, sample_rate = await generate_speech_kokoro(text, voice_id)
|
print(f"[TTS] Provider: {provider}{' (override)' if provider_override else ''}, Text: {text[:50]}...")
|
||||||
elif provider == "f5tts":
|
|
||||||
audio, sample_rate = await generate_speech_f5tts(text, voice_id)
|
gen_fn = _TTS_PROVIDERS.get(provider)
|
||||||
elif provider == "inworld":
|
if not gen_fn:
|
||||||
audio, sample_rate = await generate_speech_inworld(text, voice_id)
|
|
||||||
elif provider == "chattts":
|
|
||||||
audio, sample_rate = await generate_speech_chattts(text, voice_id)
|
|
||||||
elif provider == "styletts2":
|
|
||||||
audio, sample_rate = await generate_speech_styletts2(text, voice_id)
|
|
||||||
elif provider == "bark":
|
|
||||||
audio, sample_rate = await generate_speech_bark(text, voice_id)
|
|
||||||
elif provider == "vits":
|
|
||||||
audio, sample_rate = await generate_speech_vits(text, voice_id)
|
|
||||||
elif provider == "elevenlabs":
|
|
||||||
audio, sample_rate = await generate_speech_elevenlabs(text, voice_id)
|
|
||||||
else:
|
|
||||||
raise ValueError(f"Unknown TTS provider: {provider}")
|
raise ValueError(f"Unknown TTS provider: {provider}")
|
||||||
|
|
||||||
|
last_error = None
|
||||||
|
try:
|
||||||
|
async with asyncio.timeout(20):
|
||||||
|
for attempt in range(TTS_MAX_RETRIES):
|
||||||
|
try:
|
||||||
|
audio, sample_rate = await gen_fn(text, voice_id)
|
||||||
|
cost_tracker.record_tts_call(provider, voice_id, len(text))
|
||||||
|
if attempt > 0:
|
||||||
|
print(f"[TTS] Succeeded on retry {attempt}")
|
||||||
|
break
|
||||||
|
except TimeoutError:
|
||||||
|
raise # Let asyncio.timeout propagate
|
||||||
|
except Exception as e:
|
||||||
|
last_error = e
|
||||||
|
if attempt < TTS_MAX_RETRIES - 1:
|
||||||
|
delay = TTS_RETRY_DELAYS[attempt]
|
||||||
|
print(f"[TTS] {provider} attempt {attempt + 1} failed: {e} — retrying in {delay}s...")
|
||||||
|
await asyncio.sleep(delay)
|
||||||
|
else:
|
||||||
|
print(f"[TTS] {provider} failed after {TTS_MAX_RETRIES} attempts: {e}")
|
||||||
|
raise
|
||||||
|
except TimeoutError:
|
||||||
|
print(f"[TTS] Overall timeout (20s) for {provider}")
|
||||||
|
raise RuntimeError(f"TTS generation timed out after 20s")
|
||||||
|
|
||||||
# Apply phone filter if requested
|
# Apply phone filter if requested
|
||||||
# Skip filter for Bark - it already has rough audio quality
|
# Skip filter for Bark - it already has rough audio quality
|
||||||
if apply_filter and phone_quality not in ("none", "studio") and provider != "bark":
|
if apply_filter and phone_quality not in ("none", "studio") and provider != "bark":
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"emails": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,834 @@
|
|||||||
|
{
|
||||||
|
"lookup_history": [
|
||||||
|
{
|
||||||
|
"question": "what time is it",
|
||||||
|
"answer": "It's three oh three AM. Saturday morning.",
|
||||||
|
"tools_used": [
|
||||||
|
"get_current_time"
|
||||||
|
],
|
||||||
|
"timestamp": 1773479014.367399
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "what time is it",
|
||||||
|
"answer": "...yeah, it's three ten AM. Saturday morning.",
|
||||||
|
"tools_used": [
|
||||||
|
"get_current_time"
|
||||||
|
],
|
||||||
|
"timestamp": 1773479441.184032
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I don't know if this helps but... in a lot of states there's actually mandatory arrest laws for domestic violence calls. Like, if there's visible injury or probable cause, the officer doesn't r",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773483367.819699
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "...yeah, so that was the Brian Wells case. Pizza delivery guy in Erie, Pennsylvania, 2003. He robbed a bank with a bomb collar locked around his neck and it went off when the cops got him. The whole t",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"wikipedia_lookup"
|
||||||
|
],
|
||||||
|
"timestamp": 1773484350.1126778
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I tried to look up the fraternization rules but the search isn't working right now. But I'm pretty sure that's like, super against regulations. Recruiters aren't supposed to have personal relat",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773486225.436269
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "...yeah, so I was trying to look up the actual regulation number but the internet's being weird right now. But I'm like ninety percent sure there's a specific army reg that covers recruiter-recruit re",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773486326.583227
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "...yeah, sorry, the internet's definitely down. I was trying to get the actual reg number and the reporting hotline but nothing's loading. I think it's an issue on our end, not me, but... yeah. Sorry.",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773486425.85089
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "...yeah, sorry, still can't get online. But just so you know, even if the internet's down, that regulation definitely exists. It's like, a pretty serious violation. The anonymous tip thing would work.",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773486491.099025
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so... this actually reminds me of when I coached Little League for like three weeks in high school for community service hours, and this one dad cornered me in the parking lot and I thought he was",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773546290.2510679
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I was just looking this up and... actually most official chili cookoff rules say you can't use pre-cooked ingredients except for like, canned tomatoes and sauces. But if they're using a full ca",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773558928.104776
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I was just thinking... like, depending on the size of the town, some of these chili cookoffs actually have pretty serious prize money. The World Championship one is like a whole thing. But also",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559014.590359
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I was just looking up if there's been like, famous chili cookoff cheating before and apparently the CASI organization \u2014 that's the Chili Appreciation Society International \u2014 they actually check",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559084.318846
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so... this might not help but I was just thinking about how like, people who look perfect from the outside are usually hiding something. And Roland's finding out the Hendersons are frauds right wh",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559122.415336
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I don't know if this helps but... that whole thing about saying you're fine when you're not? My mom did that with my stepdad for like seven years and then one day she just left and moved to Tuc",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559197.542308
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I just looked it up and couples counseling actually has like a seventy percent success rate, which is pretty good. So like, three weeks isn't that long but also it kind of is if she already ask",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559220.6944141
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "...yeah, so, I don't know if this helps but I was just looking and there's actually a lot of stuff about how men specifically have trouble with the vulnerability thing in relationships. Like it's a wh",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559344.626409
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I don't know if this helps but I was just looking it up and there's actually like a whole thing about how talking and communicating are different. Like you can talk to someone every day about b",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559368.6860979
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I just looked this up and apparently gray divorce is like a whole thing now. That's what they call it when people over fifty split up. The rate has like doubled since the nineties, which is kin",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559392.036855
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so actually \u2014 average age for menopause is like 51, 52, so at 55 she'd probably be a few years post. Which, I mean, that tracks with what Luke said about the hormonal shift. This whole thing remin",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559416.509557
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so Luke actually got that right about the menopause thing. I just looked it up and yeah, the hormone shifts can genuinely change mood, personality, how someone experiences relationships. So that's",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559495.578785
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so Luke was actually right about the menopause thing. I looked it up and yeah, hormonal changes can affect mood and personality, but it's not like she became a different person per se. It's more l",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559534.719551
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I don't know if this helps but... I was looking it up and menopause does actually cause pretty significant hormonal shifts that can affect mood and communication patterns in relationships. But ",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559558.1219552
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "...um, so I don't know if this helps but I actually cheated on my astronomy final sophomore year. Like the whole thing. Had the answers written on the inside of a water bottle label. Got an A minus. S",
|
||||||
|
"tools_used": [
|
||||||
|
"get_current_time"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559641.791745
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so... this actually reminds me of when my roommate sophomore year confessed to me that he'd been lying to his girlfriend about where he went to high school for like two years, and it just spiraled",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559882.234876
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so... I don't know if this helps but I actually looked this up once after my ex told me about something she did in college like three years into us dating, and basically most relationship people s",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773559906.54929
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I don't know if this helps but... I was actually looking this up because my roommate in college had something similar happen, where his mom just like, left when he was nine, and when he turned ",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773560147.7412
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I was just looking this up because I was curious, but actually around six percent of adult children are estranged from their mothers specifically, and the research shows that kids who reach out",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773560172.2229881
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "um... so basically Disney's super aggressive about this stuff, like they'll go after anyone using their characters commercially, but if it was just a private birthday party that happened to go viral, ",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773560493.564946
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "um... so I'm trying to find if this is like an actual thing happening right now but I'm mostly just seeing the ByteDance AI stuff. But honestly this reminds me of when my ex's sister did a Frozen part",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773560517.437411
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so this actually reminds me of when my mom installed a nanny cam when I was like fourteen to see if I was the one eating all the ice cream sandwiches, but it turned out it was her the whole time a",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773561008.756311
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I don't know if this helps but... so basically she did technically commit theft, like legally speaking. Even if it's family, taking money without permission is still theft per se. I looked it u",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773561272.083394
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I don't know if this helps but I just looked it up and like, technically even if it's your dad you can still be charged with theft. It's still a crime per se. Like family members can press char",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773561296.910207
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "...yeah, um, I actually worked for a landscaping company for like three weeks in high school. Got fired because I kept showing up with the wrong kind of gloves \u2014 apparently there's a difference betwee",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773561625.01337
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I don't know if this helps but desert willows aren't actually willows, they're related to trumpet vines. Which is kind of ironic because if Diane's doing what it sounds like she's doing, she's ",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773561668.993265
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so... this might be nothing, but desert willows are actually like a resilience and adaptability thing, symbolically. Which is kind of ironic given that Earl's adapting to a situation where he mayb",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773561708.5712068
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I don't know if this is the same thing, but that reminds me of when my roommate in college just left one day without telling anyone and we found out three weeks later he'd joined this thing in ",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773562106.8085399
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I don't know if this helps but... that actually reminds me of when my mom's boyfriend left when I was like nine. Same thing, just gone one morning, didn't even take his PlayStation. We kept it ",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773562129.270505
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um... so I don't know if this helps but... I was just thinking about what Marcus said. Like, sorry for disappointing you again. That's... that's actually a pretty common thing that happens when someon",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773562209.861661
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so... I don't know if this matters, but when people leave communities without saying goodbye, it's usually because the goodbye itself would be harder than just leaving. Like, they're avoiding the ",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773562278.413093
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so... this is actually reminding me of something my therapist said once about the difference between influence and coercion, which is basically whether the person would've chosen it if they felt l",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773562752.6201081
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I just looked this up real quick and there's actually a term for this, it's called coercive control, where like, technically nothing's required but the social structure makes it so people can't",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773562777.0663989
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I looked it up and Little League actually requires annual background checks for all coaches \u2014 like, it's a national policy. They do a nationwide criminal search and check the sex offender regis",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773563354.773338
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I looked this up and... stalking behavior sometimes includes trying to get close to the target through family members or friends. Like, it's actually a documented tactic. The fact that she aske",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773646589.188498
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So I looked it up and the CDC lists approaching or showing up in places like the victim's home or workplace as an actual stalking tactic. The Demming flea market thing \u2014 if Marcus goes there regularly",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773646621.148364
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So according to the CDC, stalking tactics can include using intermediaries or approaching through family connections. The fact that she initiated contact, asked detailed family questions, and then Mar",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773646683.713517
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I found something \u2014 about 80% of stalking cases actually involve someone the victim knows, not strangers. And one of the warning signs experts list is when someone shows intense interest really",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773646769.846723
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I looked it up and there actually was a recent UK study on age play and ABDL \u2014 it's one of five major paraphilic interest groups they studied. Luke's number about 40 to 50 percent at that munch",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773647038.123303
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I looked this up \u2014 if someone's verifying a Guatemala marriage, the lawyer would typically need to authenticate the marriage certificate through the Guatemalan government and possibly get an ap",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773647372.377878
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, Guatemala had this massive adoption fraud scandal \u2014 from the 1960s through 2008, thousands of babies were stolen or coerced from Indigenous mothers. The US was aware of fraud as early as",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773647436.3055701
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, I'm not finding any actual US court cases where a Guatemalan birth mother successfully challenged custody after the adoption was finalized in the US. The legal framework is that once an ",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773647682.6634371
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, Guatemala is currently at a Level 3 travel advisory from the State Department \u2014 that's Reconsider Travel due to crime. They specifically say do not travel to certain zones in Guatemala C",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773647820.8494499
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, Luke's right that you can get a court order to prevent her from leaving, but there's also something called the Children's Passport Issuance Alert Program \u2014 it's free through the State De",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773647886.32027
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, the State Department says the US doesn't have routine exit controls \u2014 even with a court order, there's no automatic system that stops a parent at the airport. You'd need to get the emerg",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773647925.7407732
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So the State Department says you can get an emergency court order to prevent international travel, but here's the thing \u2014 the US doesn't have routine exit controls. That means even if you get a court ",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773648005.331478
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So I looked it up and emergency custody orders can actually happen pretty fast \u2014 most courts can grant them within 24 to 72 hours if there's immediate danger. Some judges will issue a temporary order ",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773648055.9440908
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, people pretend not to recognize someone for a few main reasons. Social anxiety is a big one, like they're afraid of an awkward interaction or being judged. Sometimes it's situational, li",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773648303.8702788
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, the Quora result mentions passive-aggressive behavior as a main reason people pretend not to know someone. It's a way of asserting control or sending a message without direct confrontati",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773648454.6246731
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So I looked it up and there's actually a term for this \u2014 it's called a secret friendship or hidden relationship. Psychology research shows people hide friendships from their partners for a few specifi",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773648487.007659
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I'm seeing something here \u2014 when someone compartmentalizes a friendship like this, hiding it from their spouse, relationship experts actually classify that as one of the warning signs of an emo",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773648513.5435588
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Yeah, actually \u2014 Luke's right. The caller's husband David was there, not the friend's husband. So the friend pretended not to know the caller in front of the caller's own husband, which doesn't fit th",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773648613.530808
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so the one thing I'm seeing here is that social anxiety research shows people sometimes pretend not to know someone because they're afraid of how the interaction will look to whoever's watching. I",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773648647.120529
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, if Leon's coworkers are giving him a hard time, he's actually protected under federal law. OSHA's Section 11c makes it illegal for employers to retaliate against workers who report safet",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773649150.604851
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I looked it up and OSHA actually has federal whistleblower protections specifically for this. If Leon gets retaliated against for reporting safety stuff, even like getting demoted or discipline",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773649204.095894
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, FMCSA regulations actually require physical inspection of cargo securement \u2014 you can't just eyeball it. And OSHA has whistleblower protections specifically for this kind of thing. If the",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773649256.283089
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, if this is about truck cargo securement, the caller's actually right that there are federal requirements. FMCSA regulations require drivers to physically inspect cargo and securement dev",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773649408.134513
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, if coworkers are freezing you out or creating a hostile environment because you filed an HR complaint, that can actually count as illegal retaliation \u2014 the company's responsible for stop",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773649505.8539321
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I looked it up and if he reported safety violations specifically, he's actually protected under federal law. OSHA has whistleblower protections that make it illegal for employers or coworkers t",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773649602.226942
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, so I looked this up \u2014 retaliation is actually the most common workplace complaint filed with the EEOC. In 2024 it was almost 48% of all discrimination charges, over 42,000 complaints. So basically",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773649714.304941
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, Luke was right \u2014 the U.S. Mint did stop making pennies for circulation in 2025. They actually auctioned off the last 232 circulating pennies in special sets earlier this year, if that ma",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773650025.477504
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, there's this thing called confabulation where someone genuinely believes false memories or stories they're telling. It's not technically lying because they actually think it's true. It c",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773650244.560938
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So I looked it up and actually, goblin sharks do have eyes, but the really creepy part is their jaws extend outward when they feed, like they shoot forward. And they're pink, which somehow makes it wo",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"wikipedia_lookup"
|
||||||
|
],
|
||||||
|
"timestamp": 1773650621.581631
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So I looked it up and it's about 329 miles from Deming to Phoenix, if that's where she is in Arizona. That's like five and a half hours, maybe more depending on traffic. So it's actually not that diff",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773650865.077457
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So actually, if you wanted to split the difference, there's a town called Sierra Vista that's pretty much halfway between Deming and Phoenix. It's about 30 miles from the exact midpoint. So you could ",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773650933.320225
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, you can actually snorkel without knowing how to swim if you use a life jacket or flotation vest. Most cruise excursions provide them, and they'll keep you on the surface. He should ask h",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773651077.3874822
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, you technically can snorkel without knowing how to swim because it's mostly just floating on the surface, but most cruise excursions will give you a life vest anyway, so he'd actually be",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773651141.437025
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, you can technically snorkel without swimming skills because you're mostly just floating on the surface with a life vest, but most guides say it's way riskier if you can't swim. Cruise ex",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773651186.300575
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, you can actually snorkel without knowing how to swim. Most cruise snorkeling excursions provide life jackets or flotation vests specifically for this reason. You just float on the surfac",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773651242.652043
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So basically, you can snorkel without knowing how to swim, but most guides recommend using a life jacket or flotation device, especially in open water. A lot of cruise excursions actually provide them",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773651289.880447
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "Um, one thing I found \u2014 even experienced swimmers use flotation devices for snorkeling sometimes because you can get tired in open water. So it's not gonna look weird or anything. Most people on cruis",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search",
|
||||||
|
"fetch_webpage"
|
||||||
|
],
|
||||||
|
"timestamp": 1773651465.619576
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "(interjection)",
|
||||||
|
"answer": "So actually, you're not alone at all. About half of adults worldwide can't swim unassisted. Even in high-income countries it's like one in four people. So yeah, Luke's probably right that you won't be",
|
||||||
|
"tools_used": [
|
||||||
|
"web_search"
|
||||||
|
],
|
||||||
|
"timestamp": 1773651505.359561
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"conversation_history": [
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "wheres my coffee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...yeah, sorry, I don't know where you put it. I can check if there's like a coffee shop nearby that's still open if you want? Or I guess it might be in the booth somewhere. I spilled mine earlier on that stack of papers by the soundboard but I wiped it up. That wasn't yours, right?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Where's my coffee?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...I don't know, Luke. I haven't seen it. Maybe by the mixer? Or did you leave it in the break room? I can go check if you want me to run back there real quick."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Devin, how are you doing today? I didn't get my coffee today. What's going on? It's not a very strong start, sir."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...yeah, sorry about that. I didn't know I was supposed to get you coffee. Nobody told me that was part of the job. I can go grab you something now if you want? There's that gas station like two blocks down. They have the energy drinks with the resealable caps, which, ironically, I've never actually resealed one. Just seems like you'd finish it anyway, if that makes sense."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Devin, Devin, where's my coffee? We had a long discussion yesterday about how you were going to go down to the mark and get me my black ice coffee. And you agreed. And it's not here. So what's the situation?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...yeah. Um, so basically, I thought you said Thursday. I wrote it down as Thursday. I have it in my phone and everything. I can show you. I was gonna leave like an hour before the show to make sure I got it right. I'm really sorry, Luke. I can go right now if you want. The Mark closes at like midnight, right? I'll run down there. It'll take me ten minutes. I'm sorry."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "The Merck closes at like 5 p.m. It's not open now. Come on, man. You gotta do better than this. I mean, why would I want a coffee on Thursday? You knew that we were working today. Thursday's like five days from now. How is that helpful? Come on, man."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...yeah, you're right. That doesn't make sense. I don't know why I wrote Thursday. I'm really sorry, Luke. I can go to the gas station right now, or there's that Allsup's that's open late. It won't be the same but it's something. This is my first day and I already messed up. I'm sorry. Do you want me to go now or wait until the next break?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Dude, there's no all-sups anywhere near here. There's a gas station in Road Forks 45 minutes away. By the time you went there and got back, the show would be over. That would be of no use to anybody. I need you to do better than this. Or we're going to have to get another intern."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...yeah. Got it. I'm sorry. I'll set like three alarms for tomorrow. And I'll double-check with you at the end of every shift what you need and when you need it. I wrote down The Mark, black iced coffee, before the show. I have it now. It won't happen again."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "All right, I hope not. And do you have anything to provide to the show today? Is there any reason we should have you on the air, or should you just kind of sit in the back and wait to get my coffees? Are you going to provide us some value here, or what is the deal? What are you trying to get out of this show, other than hitting on the girls I call in?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...yeah, no, I can help. I've been doing research all day, actually. I pulled like fifteen articles on that thing you mentioned yesterday about the town council meeting, and I have notes on the whole water rights situation if that comes up. And I set up the new call screening system \u2014 it's working now, I tested it like six times. I know I messed up the coffee thing, but I'm actually pretty good at the research stuff. That's kind of what I'm here for, if that makes sense. And I wasn't hitting on anyone, I was just being friendly. But yeah, I can just stay quiet if you want."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "What do you think of that, Devin? Would you go, uh, would you go do a shared intimacy night with Silas at the Wellspring?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...um. I mean, I don't really know what that is, per se, but it sounds like a couples thing? I'm not really looking to do that with Silas specifically. No offense to him or whatever, but that's not my situation. I went to one of those tantra workshops once with my ex, actually, and we got asked to leave because she wouldn't stop laughing during the eye contact part. It was like forty-five dollars and we were there for maybe twenty minutes. So I guess it depends on what the vibe is, but probably not, if that makes sense."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Yeah, I think you know what the vibe is down there at the Wellspring. It's a community with an unbinding ceremony and the intimacy nights, and they worship the flow of the current. I don't fully understand it, but Silas seems like a pretty decent dude. I think you'd like it a lot. But here's what I'm trying to get at. If you forget my coffee one more time, I'm sending you down to Silas."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...yeah, okay. Got it. I'll get the coffee. I'm not trying to go to the Wellspring. I looked it up earlier actually, when that caller mentioned it, and there's like almost no information online about it, which is kind of weird. Just a Facebook page with no posts since 2019. So I don't really know what the unbinding ceremony is, but I'm good. I'll have your coffee tomorrow, Luke. Black iced coffee from The Mark, before the show. I promise."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Devin, what did you think of today's show? Did you think this went better than yesterday's show?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...yeah, honestly I think it did. Like, yesterday felt kind of all over the place, but today people were actually calling in about stuff that mattered to them. That guy with the RV situation, and the woman talking about her sister \u2014 those felt real, if that makes sense. I don't know if the numbers were better or whatever, but it felt like people were actually listening and wanted to talk. So yeah, I think today was good. I mean, except for me forgetting your coffee. But the show itself was better."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Yeah, I think it was a pretty decent show, too. I don't know what show you were listening to, because there was no guy with an RV situation or a woman talking about her sister, so obviously you're not paying attention. But I think the show went pretty well. What do you think we should do differently for tomorrow's show? Anything? Do you have any suggestions to make the show better?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...yeah. Sorry, I don't know why I said that. I think I was thinking about yesterday or something. I was paying attention, I just got confused for a second. Um, for tomorrow... I don't know, maybe we could do like a theme or something? Like if there's a topic people are actually talking about around here, we could lead with that instead of just taking whatever calls come in. Or I could pull some local news stuff and we could have like three things ready to go in case it gets slow. I noticed today there were a couple dead spots where we were just kind of waiting. But I don't know, you're the one who's been doing this. I'm just saying what I noticed, if that makes sense."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Yeah, that makes sense. We've tried some theme-related things before. The thing is, the themes around here are, do you remember what Lordsburg used to be like 50 years ago with a picture? So that doesn't really translate that well to radio. It's kind of, I don't know, we'll see what we could do. I like the idea of the local news stuff, though. So why don't you work on that? We'll think about some local news situations and see if we can make tomorrow's show even better."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "Yeah, I can do that. I'll pull some stuff tonight and have it ready before we go on. I'll look at like the town council stuff, any county news, maybe some state things that affect people here. And I'll make sure it's actually interesting, not just like... budget reports or whatever. Things people would actually want to call in about. I'll have it organized so you can just grab whatever you need. And I'll have your coffee."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Hey, Devin, good job on the coffee this morning, buddy. I'm very proud of you. You did a great thing there, and we're all very excited that you're going to get to stay on the radio show for another day. So congratulations, and what would you like to tell the radio listeners today?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...oh. Um, thanks. I appreciate that. I guess I'd just say thanks for listening? I don't really know what to say. This is still pretty new for me, so if you have questions or want us to look something up or whatever, I'm here. I'm trying to make the show good. So yeah, thanks for calling in and being part of it. That's all I got."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "I think you've got it all wrong. There is no close friendship with the marriage guy. Let me explain this to you, Devin, because obviously you're missing it. So, Sheila and Monica were friends in high school. And in this interaction, Sheila is with her husband, David. David and Sheila are married. And Monica was there and pretended not to know Sheila, even though they've been hanging out for weeks and weeks at coffee shops and stuff. So they have an ongoing platonic friendship going on, and when witnessed in the shopping area, Monica pretended not to know Sheila. And that's just very strange. It doesn't fit these patterns that you're describing to us."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "Right, yeah \u2014 I had it backwards. Sorry. So if Monica pretended not to know Sheila in front of David, and Monica's the one who's married... maybe Monica's husband doesn't know about the friendship? Like she's been meeting Sheila without telling him, and she panicked when she saw someone who knows her. That would explain why she acted like strangers. She's hiding the friendship from her own husband, not from Sheila's."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Devin, that's the end of another show. How are you feeling about this? You've been with us for three days now. You did a much better job today than your first couple of days. I'm proud of you, buddy, and you brought my coffee, and that was very good. This might be working out. What are your thoughts on the show? And how do you think it went?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Devin, that's the end of another show. How are you feeling about this? You've been with us for three days now. You did a much better job today than your first couple of days. I'm proud of you, buddy, and you brought my coffee, and that was very good. This might be working out. What are your thoughts on the show? And how do you think it went?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "...thanks. That actually means a lot. I was really worried I was screwing everything up the first couple days. Um, I think today was solid. Like, the Monica and Sheila thing was interesting, and people seemed to actually care about calling in. I still messed up a couple times, but I'm getting better at knowing when to jump in and when to just let you handle it. And I have the local news stuff ready for tomorrow, so hopefully that helps keep things moving. I'm just trying to be useful, you know? This job is actually really important to me. My mom keeps asking if I'm gonna get fired, so it's nice to hear you say it might be working out. I'll keep the coffee coming."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "All right, you keep the coffee coming and we'll be okay. As soon as you stop bringing that coffee, though, I mean, I'm going to get an intern that can do it. So I'm proud of you. You're doing a good job. You're adding to the show, and I like that. Do you have anything you'd like to say to the audience before we leave?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "Um, yeah. Thanks for listening. And if you have stuff you want us to talk about tomorrow, or like weird situations you need help figuring out, call in. That's what we're here for. I'll have the local news ready and Luke will... do what he does. So yeah, thanks. Have a good night, I guess."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
{
|
||||||
|
"31": {
|
||||||
|
"steps": {
|
||||||
|
"castopod": {
|
||||||
|
"completed_at": "2026-03-08T10:00:02.383893+00:00",
|
||||||
|
"episode_id": "33",
|
||||||
|
"slug": "episode-31-boundaries-breakups-and-borrowed-books"
|
||||||
|
},
|
||||||
|
"social": {
|
||||||
|
"completed_at": "2026-03-08T10:14:48.779760+00:00"
|
||||||
|
},
|
||||||
|
"youtube": {
|
||||||
|
"completed_at": "2026-03-08T10:36:24.024343+00:00",
|
||||||
|
"video_id": "KcGb9ttsIpo"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"started_at": "2026-03-08T10:00:02.383873+00:00"
|
||||||
|
},
|
||||||
|
"32": {
|
||||||
|
"steps": {
|
||||||
|
"castopod": {
|
||||||
|
"completed_at": "2026-03-09T09:43:52.540238+00:00",
|
||||||
|
"episode_id": 34,
|
||||||
|
"slug": "episode-32-tacos-taxes-and-tall-tales"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"started_at": "2026-03-09T09:43:52.540200+00:00"
|
||||||
|
},
|
||||||
|
"33": {
|
||||||
|
"steps": {
|
||||||
|
"castopod": {
|
||||||
|
"completed_at": "2026-03-11T11:34:31.871604+00:00",
|
||||||
|
"episode_id": "36",
|
||||||
|
"slug": "episode-33-late-night-confessions-and-cosmic-comedies"
|
||||||
|
},
|
||||||
|
"youtube": {
|
||||||
|
"completed_at": "2026-03-11T11:50:49.212276+00:00",
|
||||||
|
"video_id": "KrJshN3cuBU"
|
||||||
|
},
|
||||||
|
"social": {
|
||||||
|
"completed_at": "2026-03-11T11:50:53.641920+00:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"started_at": "2026-03-09T10:18:16.606019+00:00"
|
||||||
|
},
|
||||||
|
"34": {
|
||||||
|
"steps": {
|
||||||
|
"castopod": {
|
||||||
|
"completed_at": "2026-03-12T07:04:34.974478+00:00",
|
||||||
|
"episode_id": "37",
|
||||||
|
"slug": "episode-34-hidden-rooms-potlucks-and-mysterious-notes"
|
||||||
|
},
|
||||||
|
"youtube": {
|
||||||
|
"completed_at": "2026-03-12T07:17:53.453882+00:00",
|
||||||
|
"video_id": "tNcABnYpf-c"
|
||||||
|
},
|
||||||
|
"social": {
|
||||||
|
"completed_at": "2026-03-12T07:17:57.131871+00:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"started_at": "2026-03-12T07:04:34.974425+00:00"
|
||||||
|
},
|
||||||
|
"35": {
|
||||||
|
"steps": {
|
||||||
|
"castopod": {
|
||||||
|
"completed_at": "2026-03-13T11:19:41.765107+00:00",
|
||||||
|
"episode_id": 38,
|
||||||
|
"slug": "episode-35-midnight-confessions-and-unexpected-revelations"
|
||||||
|
},
|
||||||
|
"youtube": {
|
||||||
|
"completed_at": "2026-03-13T11:42:00.428623+00:00",
|
||||||
|
"video_id": "fYvXLqFilLQ"
|
||||||
|
},
|
||||||
|
"social": {
|
||||||
|
"completed_at": "2026-03-13T11:42:11.800641+00:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"started_at": "2026-03-13T11:19:41.765079+00:00"
|
||||||
|
},
|
||||||
|
"36": {
|
||||||
|
"steps": {
|
||||||
|
"castopod": {
|
||||||
|
"completed_at": "2026-03-14T12:01:15.758700+00:00",
|
||||||
|
"episode_id": "39",
|
||||||
|
"slug": "episode-36-late-night-confessions-and-unexpected-moments"
|
||||||
|
},
|
||||||
|
"youtube": {
|
||||||
|
"completed_at": "2026-03-14T12:25:36.640461+00:00",
|
||||||
|
"video_id": "BabWoKFt0pk"
|
||||||
|
},
|
||||||
|
"social": {
|
||||||
|
"completed_at": "2026-03-14T12:25:44.192676+00:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"started_at": "2026-03-14T12:01:15.758670+00:00"
|
||||||
|
},
|
||||||
|
"37": {
|
||||||
|
"steps": {
|
||||||
|
"castopod": {
|
||||||
|
"completed_at": "2026-03-15T09:07:26.659541+00:00",
|
||||||
|
"episode_id": "40",
|
||||||
|
"slug": "episode-37-secrets-lies-and-coffee-runs"
|
||||||
|
},
|
||||||
|
"youtube": {
|
||||||
|
"completed_at": "2026-03-15T09:33:48.299549+00:00",
|
||||||
|
"video_id": "XW7Q0WPzNqY"
|
||||||
|
},
|
||||||
|
"social": {
|
||||||
|
"completed_at": "2026-03-15T09:34:02.069440+00:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"started_at": "2026-03-15T09:07:26.659508+00:00"
|
||||||
|
},
|
||||||
|
"38": {
|
||||||
|
"steps": {
|
||||||
|
"castopod": {
|
||||||
|
"completed_at": "2026-03-16T10:08:51.467004+00:00",
|
||||||
|
"episode_id": 41,
|
||||||
|
"slug": "episode-38-secrets-lies-and-late-night-confessions"
|
||||||
|
},
|
||||||
|
"youtube": {
|
||||||
|
"completed_at": "2026-03-16T10:30:31.775891+00:00",
|
||||||
|
"video_id": "6qLsJxnCLs0"
|
||||||
|
},
|
||||||
|
"social": {
|
||||||
|
"completed_at": "2026-03-16T10:30:41.220832+00:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"started_at": "2026-03-16T10:08:51.466898+00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,296 +1,318 @@
|
|||||||
{
|
{
|
||||||
"regulars": [
|
"regulars": [
|
||||||
{
|
{
|
||||||
"id": "dc4916a7",
|
"id": "0a0b3635",
|
||||||
"name": "Leon",
|
"name": "Charlene",
|
||||||
"gender": "male",
|
|
||||||
"age": 56,
|
|
||||||
"job": "and last week his daughter asked him why he never went back to school for programming like he always talked about\u2014she found his old acceptance letter from UNM's CS program tucked",
|
|
||||||
"location": "unknown",
|
|
||||||
"personality_traits": [],
|
|
||||||
"call_history": [
|
|
||||||
{
|
|
||||||
"summary": "Leon, a 63-year-old tow truck driver, called in feeling regretful after pulling a young remote worker's Tesla from a ditch, which reminded him of the computer science acceptance letter he never acted on in 1996 when his girlfriend got pregnant. The conversation became emotional as Leon realized he's the same age his father was when he died, and the host challenged him to stop making excuses and finally pursue the tech career he's been thinking about for decades instead of just \"wondering what could have been.\"",
|
|
||||||
"timestamp": 1770693549.697355
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "Leon called back to share that he reached out to UNM about their computer science program and is now deciding between an online bootcamp (which he and his wife Amber can afford without loans) versus a full degree program, ultimately leaning toward the bootcamp since he struggles with self-teaching. He expressed nervousness but appreciation for his daughter holding him accountable, and emotionally shared that buying his reliable used Subaru five years ago changed his life by giving him confidence and reducing stress at his towing job.",
|
|
||||||
"timestamp": 1770951992.186027
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "In this brief clip, the host begins to set up a game with caller Vence, starting to explain the rules before the audio cuts off. There's no substantive conversation or emotional content to summarize.",
|
|
||||||
"timestamp": 1771119313.497329
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "Leon called in to play a dating profile game but revealed he's struggling with his coding bootcamp because he's more interested in studying poker strategy than Python. The host encouraged him that at 56, he could pursue becoming a poker pro just as much as anything else, which seemed to resonate with Leon emotionally as he realized poker is what he actually wants to do rather than what he thinks he should do.",
|
|
||||||
"timestamp": 1771119607.065818
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"last_call": 1771119607.065818,
|
|
||||||
"created_at": 1770693549.697355,
|
|
||||||
"voice": "CwhRBWXzGAHq8TQ4Fs17"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "584767e8",
|
|
||||||
"name": "Carl",
|
|
||||||
"gender": "male",
|
|
||||||
"age": 36,
|
|
||||||
"job": "is a firefighter",
|
|
||||||
"location": "unknown",
|
|
||||||
"personality_traits": [],
|
|
||||||
"call_history": [
|
|
||||||
{
|
|
||||||
"summary": "Carl, a firefighter from Lordsburg, New Mexico, called to confess his 20-year gambling addiction, which began with casual poker games at the station and escalated to frequent casino visits and online sessions, draining his finances and leaving him with overdue bills and the fear of losing his home. Emotionally raw, he admitted the habit's destructive hold\u2014like an unquenchable fire\u2014and his pride in avoiding help, but agreed to consider support groups and an 800 hotline after the host suggested productive alternatives like gym workouts or extra volunteer shifts.",
|
|
||||||
"timestamp": 1770522170.1887732
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "Here is a 1-2 sentence summary of the radio call:\n\nThe caller, Carl, discusses his progress in overcoming his gambling addiction, including rewatching The Sopranos, but the host, Luke, disagrees with Carl's high opinion of the show's ending, leading to a back-and-forth debate between the two about the merits and predictability of the Sopranos finale.",
|
|
||||||
"timestamp": 1770573289.82847
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "Carl, a firefighter, called to discuss finding $15-20,000 in cash at a house fire and struggling with the temptation to keep it despite doing the right thing by returning it to the family. He's been gambling-free for three months but is financially struggling, and though he returned the money, he's been losing sleep for three nights obsessing over what he could have done with it and fearing he might have blown it at a casino anyway.",
|
|
||||||
"timestamp": 1770694065.5629818
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"last_call": 1770694065.5629828,
|
|
||||||
"created_at": 1770522170.1887732,
|
|
||||||
"voice": "SOYHLrjzK2X1ezoPC6cr"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "04b1a69c",
|
|
||||||
"name": "Reggie",
|
|
||||||
"gender": "male",
|
|
||||||
"age": 51,
|
|
||||||
"job": "a 39-year-old food truck operator, is reeling from a troubling discovery this morning",
|
|
||||||
"location": "in unknown",
|
|
||||||
"personality_traits": [],
|
|
||||||
"call_history": [
|
|
||||||
{
|
|
||||||
"summary": "Reggie called in worried because his partner suddenly packed a bag and left for her mom's house without explanation and won't answer his calls, making him fear something is wrong with their relationship. The host advised him to stop calling repeatedly and have a calm conversation with her when she's ready to talk, reassuring him he's likely overreacting.",
|
|
||||||
"timestamp": 1770769705.511872
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"last_call": 1770769705.511872,
|
|
||||||
"created_at": 1770769705.511872,
|
|
||||||
"voice": "N2lVS1w4EtoT3dr4eOWO"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "747c6464",
|
|
||||||
"name": "Brenda",
|
|
||||||
"gender": "female",
|
"gender": "female",
|
||||||
"age": 44,
|
"age": 42,
|
||||||
"job": "a 41-year-old ambulance driver, is fed up with the tipping culture",
|
"job": "killing time during a three-hour mechanical delay while her crew naps",
|
||||||
"location": "unknown",
|
"location": "unknown",
|
||||||
"personality_traits": [],
|
"personality_traits": [],
|
||||||
|
"voice": "Amina",
|
||||||
|
"stable_seeds": {
|
||||||
|
"style": "COMMUNICATION STYLE: Everything circles back to them and how great they are. Name drops. Mentions their truck, their property, their salary, their bench press. Not overtly obnoxious \u2014 they genuinely think they're being conversational. Energy level: medium-high. When pushed back on, they get defensive fast and start listing accomplishments. Conversational tendency: one-upping."
|
||||||
|
},
|
||||||
"call_history": [
|
"call_history": [
|
||||||
{
|
{
|
||||||
"summary": "Brenda called in to vent about being frustrated with automatic tipping at a diner, where a 20% tip was already added to her bill but the card reader prompted her to add an additional 25-35% while the waitress watched. She expressed feeling pressured and annoyed as an ambulance driver with two kids, struggling with whether to look cheap by reducing the tip, before playing a quick real-or-fake news game with the host.",
|
"summary": "Charlene bought a house eight months ago and keeps receiving mail for the previous resident, David Herrera, including a certified letter she accidentally signed for containing what appears to be a $12,000-13,000 check. Despite her attempts to resolve it with the post office and her inclination to track him down via Facebook, the host advises her to either hold it until David contacts her, return it to the post office, or discard it, warning that she can't be certain she'd find the correct person online.",
|
||||||
"timestamp": 1770770008.684104
|
"timestamp": 1772866520.023335
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"summary": "Brenda called in still thinking about whether a waitress remembered her tipping situation from two weeks ago, admitting she cares too much about what strangers think of her. The conversation revealed she's been avoiding dating entirely while working long shifts and dealing with family obligations, acknowledging she obsesses over small social interactions instead of actually putting herself out there romantically.",
|
"summary": "Charlene called to report that she's been closely tracking a mail carrier who regularly visits her neighbor's house for extended periods while the neighbor's husband is at work, implying she suspects an affair and is unsure whether she should tell anyone about what she's observed.",
|
||||||
"timestamp": 1771120062.169228
|
"timestamp": 1773219255.916183
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"last_call": 1771120062.169229,
|
"last_call": 1773219255.9161851,
|
||||||
"created_at": 1770770008.684105,
|
"created_at": 1772866520.023336
|
||||||
"voice": "hpp4J3VqNfWAUOO0d1Us"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "add59d4a",
|
"id": "0bb02b2d",
|
||||||
"name": "Rick",
|
"name": "Chip",
|
||||||
"gender": "male",
|
"gender": "male",
|
||||||
"age": 65,
|
"age": 23,
|
||||||
"job": "south of Silver City",
|
"job": "watching his kid's soccer uniform tumble in the dryer while his girlfriend works the graveyard shift at the hospital, because three hours ago he got an email from a lawyer representing families",
|
||||||
"location": "unknown",
|
"location": "unknown",
|
||||||
"personality_traits": [],
|
"personality_traits": [],
|
||||||
|
"voice": "Sebastian",
|
||||||
|
"stable_seeds": {
|
||||||
|
"style": "COMMUNICATION STYLE: Amped up. Talks fast, laughs loud, jumps between topics like they've had five espressos. Infectious enthusiasm \u2014 even bad news sounds exciting when they tell it. Uses exclamation energy without actually exclaiming. Energy level: very high. When pushed back on, they get even MORE animated and start talking with their hands (you can hear it). Conversational tendency: escalation."
|
||||||
|
},
|
||||||
"call_history": [
|
"call_history": [
|
||||||
{
|
{
|
||||||
"summary": "Rick called in to play \"real news or fake news\" and correctly identified a headline about a geothermal plant sale. He then shared that he's troubled about an elderly bank customer who withdrew $8,000 cash while appearing scared and mentioning his daughter's boyfriend was pressuring him about finances\u2014Rick processed the withdrawal but later learned he should have flagged it as potential elder exploitation, and he's feeling guilty about not intervening.",
|
"summary": "Chip called from a laundromat at midnight after receiving an email from a Guatemalan lawyer claiming his adopted 8-year-old daughter may have been stolen from her birth mother, with a photo showing a woman with his daughter's exact crooked smile. The host advised him not to panic, treat the information as suspect until verified by a lawyer, wait to tell both his girlfriend and daughter until he knows more facts, and reminded him that fake photos are easy to create and this could be a scam.",
|
||||||
"timestamp": 1770771655.536344
|
"timestamp": 1772786610.885828
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"summary": "Rick, a 65-year-old caller, is asked to evaluate a dating profile for 29-year-old Angela, a \"girl mom\" and MLM skin care seller with strong Christian values. He quickly passes due to the extreme age gap and her intense focus on recruiting for her \"not a pyramid scheme\" business, though he says he'd reconsider if she toned down the sales pitch and religious intensity.",
|
"summary": "Chip called about discovering his adopted daughter may have been stolen from her birth mother in Guatemala, and he's paralyzed about telling his girlfriend Teresa, fearing it will end their already rocky relationship. He's anxious about the timing and the birth mother's request to meet their daughter, but the host advised him to take his time, have the conversation with Teresa, and make decisions together as parents.",
|
||||||
"timestamp": 1771126337.585641
|
"timestamp": 1772962156.544322
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"summary": "The caller, **Chip**, shared his emotional turmoil over discovering that his **adopted daughter\u2019s birth mother** may have resurfaced after receiving an unverified email with a photo that eerily matched his daughter\u2019s features. His girlfriend, **Teresa**, had known about the email for **three weeks** but kept it from him, leaving him feeling betrayed and overwhelmed. While Chip wants to **verify the claim legally before acting**, Teresa insists on **immediately flying to Guatemala with their daughter** to meet the woman, dismissing his fears as avoidance. The conversation escalated into a heated debate about **trust, safety, and extreme measures**\u2014with the host, Luke, urging Chip to **file a restraining order** if Teresa refuses to back down, warning of potential dangers in Guatemala. Chip, torn between **protecting his family and avoiding a nuclear confrontation**, vowed to try reasoning with Teresa one last time before she leaves for work. The call was charged with **fear, frustration, and the weight of a decision that could reshape their family forever**.",
|
||||||
|
"timestamp": 1773226361.4859362
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"summary": "Chip called to update Luke about his adoption situation: his lawyer verified that his daughter's Guatemalan adoption may have been part of a fraud scandal, and now his girlfriend Teresa has secretly bought plane tickets to take their daughter to Guatemala this Friday to meet the birth mother. Despite Luke's strong advice to get an emergency court order to prevent the trip for safety reasons, Chip is torn because Teresa threatened to leave him if he stops her, though he ultimately acknowledges the relationship is likely over either way.",
|
||||||
|
"timestamp": 1773648139.8094652,
|
||||||
|
"arc_status": "ongoing"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"last_call": 1771126337.585642,
|
"last_call": 1773648139.8094661,
|
||||||
"created_at": 1770771655.536344,
|
"created_at": 1772786610.8858292
|
||||||
"voice": "TX3LPaxmHKxFdv7VOQHJ"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "13ff1736",
|
"id": "3721ebf2",
|
||||||
"name": "Jasmine",
|
"name": "Maxine",
|
||||||
"gender": "female",
|
|
||||||
"age": 36,
|
|
||||||
"job": "a 61-year-old woman who runs a small bakery in the rural Southwest, finds herself at a crossroads",
|
|
||||||
"location": "unknown",
|
|
||||||
"personality_traits": [],
|
|
||||||
"call_history": [
|
|
||||||
{
|
|
||||||
"summary": "Jasmine called in to defend an earlier caller (Rick) whom she felt the host was too hard on, explaining she's been feeling guilty herself lately. She emotionally revealed that she chose her 1972 Ford Bronco restoration project over her marriage when given an ultimatum, and now regrets sleeping in the guest room with Valentine's Day approaching.",
|
|
||||||
"timestamp": 1770772286.1733272
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "Jasmine called to update Luke about her relationship with David after previously discussing their issues over her Ford Bronco obsession. David invited her to watch a SpaceX launch together before Valentine's Day, but she's anxious it will be awkward since they've barely talked in weeks, though Luke convinces her to just enjoy the moment together without forcing conversation.",
|
|
||||||
"timestamp": 1771033676.7729769
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"last_call": 1771033676.7729769,
|
|
||||||
"created_at": 1770772286.1733272,
|
|
||||||
"voice": "pFZP5JQG7iQjIQuC4Bku"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "f21d1346",
|
|
||||||
"name": "Andre",
|
|
||||||
"gender": "male",
|
|
||||||
"age": 54,
|
|
||||||
"job": "is a firefighter unknown",
|
|
||||||
"location": "in unknown",
|
|
||||||
"personality_traits": [],
|
|
||||||
"call_history": [
|
|
||||||
{
|
|
||||||
"summary": "Andre called into a radio game show but first shared that he's upset about being named in court documents related to a lawsuit involving a family he helped in December by returning $15,000 after a house fire. Though the host reassured him he has nothing to worry about since he did the right thing, Andre expressed frustration that his good deed led to him being dragged into an insurance dispute.",
|
|
||||||
"timestamp": 1770770944.7940538
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "Andre calls back with an update: the lawsuit against him was dropped, and the family he helped sent him a card with $500 cash, which makes him feel conflicted about accepting payment for doing the right thing. On a positive note, he's been gambling-free for two months and attending meetings, and Luke encourages him to keep the money or donate it, celebrating his progress.",
|
|
||||||
"timestamp": 1770870907.493257
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"last_call": 1770870907.493258,
|
|
||||||
"created_at": 1770770944.7940538,
|
|
||||||
"voice": "JBFqnCBsd6RMkjVDRZzb"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "d97cb6f9",
|
|
||||||
"name": "Carla",
|
|
||||||
"gender": "female",
|
"gender": "female",
|
||||||
"age": 26,
|
"age": 26,
|
||||||
"job": "is a vet tech",
|
"job": "and the math doesn't add up\u2014there's a six-foot gap between her bedroom and the bathroom that shouldn't exist, and when she finally pried open the door she thought led to a closet, it was just drywall, fresh enough that she could smell the joint compound",
|
||||||
"location": "unknown",
|
"location": "in unknown",
|
||||||
"personality_traits": [],
|
"personality_traits": [],
|
||||||
|
"voice": "Kelsey",
|
||||||
|
"stable_seeds": {
|
||||||
|
"style": "COMMUNICATION STYLE: Quiet, a little nervous. Short sentences, lots of pauses. Doesn't volunteer information \u2014 you have to pull it out of them. When they do open up it comes out in a rush. Gets flustered by direct questions. Tends to backtrack and qualify everything they say. Energy level: low. When pushed back on, they fold quickly and agree even if they don't mean it. Conversational tendency: understatement."
|
||||||
|
},
|
||||||
"call_history": [
|
"call_history": [
|
||||||
{
|
{
|
||||||
"summary": "Carla, separated from her husband but not yet divorced, vented about her intrusive in-laws who relentlessly call and dictate her life\u2014from finances and household matters to her clothing choices\u2014while her spineless spouse relays their demands, making her feel trapped in a one-sided war. With her own parents unavailable (father deceased, mother distant), she leans on her bickering but honest sister for support, underscoring her deep frustration and sense of isolation.",
|
"summary": "Maxine called after discovering a hidden 6-foot space behind a sealed door in her house, and when she cut through the drywall, she found multiple boxes filled with banded stacks of $20 bills from the 1990s\u2014potentially tens or hundreds of thousands of dollars left by the previous owner who died there. She struggled with whether to keep the money or contact the deceased owner's family, with the host arguing it was legally hers since she bought the house \"as-is,\" though Maxine remained conflicted about what felt morally right.",
|
||||||
"timestamp": 1770522530.8554251
|
"timestamp": 1773395481.8522182
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "Carla dismissed celebrity science theories like Terrence Howard's after watching Neil deGrasse Tyson's critique, then marveled at JWST's exoplanet discoveries before sharing her relief at finally cutting off her toxic in-laws amid her ongoing divorce. She expressed deep heartbreak over actor James Ransone's suicide at 46, reflecting on life's fragility, her late father's death, and the need to eliminate family drama, leaving her contemplative and planning a solo desert drive for clarity.",
|
|
||||||
"timestamp": 1770526316.004708
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "In this call, Carla discovered some explicit photos of her ex-husband and his old girlfriend in a box of his old ham radio equipment. She is feeling very uncomfortable about the situation and is seeking advice from the radio host, Luke, on how to best handle and dispose of the photos.",
|
|
||||||
"timestamp": 1770602323.234795
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "Carla called with an update about burning the explicit photos of her ex-husband and his old girlfriend, revealing that the girlfriend unexpectedly messaged her on Facebook to \"clear the air\" after apparently hearing about the situation through Carla's previous radio call. When Luke asked about her most embarrassing masturbation material, Carla admitted to using historical romance novels during her failing marriage, explaining she was drawn to the fantasy of men who actually cared and paid attention, unlike her ex-husband who ignored her to play video games.",
|
|
||||||
"timestamp": 1770871317.049056
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "Okay, here's a 1-2 sentence summary of the radio call:\n\nThe caller, Carla, was asked to give her honest opinion on a dating profile for a man named Todd. After reviewing the profile, Carla politely declined, explaining that the profile seemed a bit \"try-hard\" for her tastes, and outlined the qualities she would prefer in a potential date, such as a good sense of humor and an adventurous spirit. The host acknowledged that Carla was not interested in dating Todd.",
|
|
||||||
"timestamp": 1771121545.873672
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"last_call": 1771121545.873673,
|
"last_call": 1773395481.8522189,
|
||||||
"created_at": 1770522530.855426,
|
"created_at": 1773395481.8522189
|
||||||
"voice": "FGY2WhTYpPnrIDTdsKH5"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "7be7317c",
|
"id": "7ed14071",
|
||||||
"name": "Jerome",
|
"name": "Thelma",
|
||||||
"gender": "male",
|
|
||||||
"age": 53,
|
|
||||||
"job": "phone",
|
|
||||||
"location": "unknown",
|
|
||||||
"personality_traits": [],
|
|
||||||
"call_history": [
|
|
||||||
{
|
|
||||||
"summary": "Jerome, a police officer in Texas, called from a DQ parking lot worried about AI writing police reports after his son sent him an article suggesting it might replace him. Through the conversation, he moved from fear about accountability and accuracy in criminal cases to acknowledging that AI handling routine paperwork (like cattle complaints) could free him up to do more meaningful police work in his understaffed county, though he remains uncertain about where this technology will lead.",
|
|
||||||
"timestamp": 1770692087.560522
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "The caller described a turbulent couple of weeks, mentioning an issue with AI writing police reports, which he suggested was just the beginning of a larger problem. He seemed concerned about the developments and wanted to discuss the topic further with the host.",
|
|
||||||
"timestamp": 1770892192.893108
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"last_call": 1770892192.89311,
|
|
||||||
"created_at": 1770692087.560523,
|
|
||||||
"voice": "IKne3meq5aSn9XLyUdCD"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "f383d29b",
|
|
||||||
"name": "Megan",
|
|
||||||
"gender": "female",
|
"gender": "female",
|
||||||
"age": 34,
|
"age": 30,
|
||||||
"job": "which got her thinking about her sister Crystal up in Flagstaff who hasn't seen a truly dark sky",
|
"job": "works the front desk at a hotel",
|
||||||
"location": "unknown",
|
"location": "unknown",
|
||||||
"personality_traits": [],
|
"personality_traits": [
|
||||||
|
"weirdly cheerful for someone with this problem",
|
||||||
|
"does amateur radio astronomy, built their own antenna",
|
||||||
|
"into off-roading, knows every dirt road in the county",
|
||||||
|
"weirdly cheerful for someone with this problem"
|
||||||
|
],
|
||||||
|
"voice": "Wendy",
|
||||||
|
"stable_seeds": {
|
||||||
|
"style": "COMMUNICATION STYLE: Amped up. Talks fast, laughs loud, jumps between topics like they've had five espressos. Infectious enthusiasm \u2014 even bad news sounds exciting when they tell it. Uses exclamation energy without actually exclaiming. Energy level: very high. When pushed back on, they get even MORE animated and start talking with their hands (you can hear it). Conversational tendency: escalation."
|
||||||
|
},
|
||||||
|
"structured_background": {
|
||||||
|
"name": "Thelma",
|
||||||
|
"age": 30,
|
||||||
|
"gender": "female",
|
||||||
|
"job": "works the front desk at a hotel",
|
||||||
|
"location": null,
|
||||||
|
"reason_for_calling": "their kid graduated basic training today and they've never been more proud or more terrified",
|
||||||
|
"pool_name": "CELEBRATIONS",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Amped up. Talks fast, laughs loud, jumps between topics like they've had five espressos. Infectious enthusiasm \u2014 even bad news sounds exciting when they tell it. Uses exclamation energy without actually exclaiming. Energy level: very high. When pushed back on, they get even MORE animated and start talking with their hands (you can hear it). Conversational tendency: escalation.",
|
||||||
|
"energy_level": "medium",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "weirdly cheerful for someone with this problem",
|
||||||
|
"situation_summary": "their kid graduated basic training today and they've never been more proud or more terrified",
|
||||||
|
"natural_description": "30, works the front desk at a hotel. Their kid graduated basic training today and they've never been more proud or more terrified. Her ex-husband danny, he's still in the picture because of the kids. Cheerful and joking at first. Using humor to avoid the real thing. Eventually drops the act.. Thinks dogs are better judges of character than people. Tends to say \"just another Tuesday.\" Having sipping on some mezcal a friend brought back from across the border.. Misses the old Denny's that used to be in Lordsburg, it wasn't good but it was there Dating around. Nothing serious. Prefers it that way, mostly.. Drives a Ram. Weirdly cheerful for someone with this problem. Her best friend lena, who moved away last year and the distance is hard. Was was up late painting \u2014 walls, not art \u2014 and had the radio on for company. before calling. Into does amateur radio astronomy, built their own antenna. Heard a caller earlier tonight and it hit close to home. Had to pick up the phone.. It's Saturday night, way too late \u2014 almost morning. it's the weekend. Early spring \u2014 wind season is starting. Dust storms possible.",
|
||||||
|
"seeds": [
|
||||||
|
"does amateur radio astronomy, built their own antenna",
|
||||||
|
"into off-roading, knows every dirt road in the county",
|
||||||
|
"weirdly cheerful for someone with this problem",
|
||||||
|
"Thinks dogs are better judges of character than people."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": "in the walk-in cooler because it's the only quiet spot"
|
||||||
|
},
|
||||||
|
"avatar": "Thelma.jpg",
|
||||||
|
"relationships": {},
|
||||||
"call_history": [
|
"call_history": [
|
||||||
{
|
{
|
||||||
"summary": "Megan, a kindergarten teacher from the bootheel, called in after one of her students asked if stars know we're looking at them, which led her to reflect on how her sister Crystal in Flagstaff has stopped appreciating the night sky despite having access to it. The conversation took an unexpected turn when Luke challenged her to admit a gross habit, and after some prodding, she confessed to picking dry skin off her feet while watching TV and flicking it on the floor.",
|
"summary": "Thelma called concerned that her 19-year-old daughter Jessie, who just graduated basic training, has been exchanging romantic messages on Instagram with her army recruiter (a man in his 30s-40s), which violates military regulations. She's conflicted because she discovered this through a secret burner account and admits she wants to tell Jessie's father partly to prove him wrong for pushing their daughter to enlist, though she ultimately agrees to make an anonymous report instead.",
|
||||||
"timestamp": 1770870641.723117
|
"timestamp": 1773486573.146657,
|
||||||
},
|
"arc_status": "ongoing"
|
||||||
{
|
|
||||||
"summary": "Here is a 1-2 sentence summary of the call:\n\nThe caller, Megan, is following up on a previous call about her sister Crystal, who lives in Flagstaff and has lost appreciation for the night sky. Megan seems eager to provide an update on the situation with her sister.",
|
|
||||||
"timestamp": 1770894505.175125
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "In summary, the caller presented a dating profile for a 63-year-old man named Frank who loves making birdhouses. The host, Megan, gave her honest assessment - she appreciated some aspects of Frank's profile, like his openness about his situation, but had reservations about his intense birdhouse obsession. Megan seemed unsure if they would be a good match, despite the host's attempts to get her to consider dating Frank under different hypothetical circumstances. The conversation focused on Megan's reaction to Frank's profile and her hesitation about pursuing a relationship with him.",
|
|
||||||
"timestamp": 1771122973.966489
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"last_call": 1771122973.96649,
|
"last_call": 1773486573.146658,
|
||||||
"created_at": 1770870641.723117,
|
"created_at": 1773486573.146658
|
||||||
"voice": "cgSgspJ2msm6clMCkdW9"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "49147bd5",
|
"id": "bbb20b67",
|
||||||
"name": "Keith",
|
"name": "Angie",
|
||||||
"gender": "male",
|
"gender": "female",
|
||||||
"age": 61,
|
"age": 28,
|
||||||
"job": "south of Silver City",
|
"job": "watching her coveralls tumble dry and trying to decide if she should drive the three hours to Tucson tomorrow for her mom's birthday or keep pretending her brother doesn't exist",
|
||||||
"location": "in unknown",
|
"location": "in unknown",
|
||||||
"personality_traits": [],
|
"personality_traits": [],
|
||||||
|
"voice": "Julia",
|
||||||
|
"stable_seeds": {
|
||||||
|
"style": "COMMUNICATION STYLE: Bone dry. Says devastating things with zero inflection. Their humor sneaks up on you \u2014 you're not sure if they're joking until three seconds after they finish talking. Short, precise sentences. Never raises their voice. Energy level: low-medium. When pushed back on, they respond with one calm sentence that somehow makes the other person feel stupid. Conversational tendency: underreaction."
|
||||||
|
},
|
||||||
"call_history": [
|
"call_history": [
|
||||||
{
|
{
|
||||||
"summary": "The caller, Luke, kicked off by sharing a humorous clip of Terrence Howard's Tree of Life Theory being critiqued by Neil deGrasse Tyson, which left Howard visibly hurt, before pivoting to economic woes, blaming overspending and Federal Reserve money printing for devaluing the currency and harming everyday people. He advocated abolishing the Fed, echoing Ron Paul's ideas, to let markets stabilize money, potentially boosting innovation and new industries in rural spots like Silver City despite uncertain local impacts.",
|
"summary": "Angie's dying mother wants her to have birthday dinner with her estranged brother Derek tomorrow, whom she hasn't spoken to in two years after he told their mother her cancer was \"God's way of getting her attention\" for voting for Biden. Despite her fear that Derek will say something hurtful during dinner and her past trauma from staying silent around him, Angie agrees to go and share cake with her mother, deciding to buy the relighting candles her mom loved when they were kids.",
|
||||||
"timestamp": 1770524506.3390348
|
"timestamp": 1772862907.314721
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"summary": "Here is a 1-2 sentence summary of the call:\n\nThe caller, who works at a bank, has been reflecting on his tendency to blame the government and economic system for his problems, rather than taking responsibility for his own role. He had an epiphany while eating leftover enchiladas in his minivan, realizing he needs to be more proactive instead of just complaining.",
|
"summary": "Angie called back after having the birthday cake dinner with her dying mom, which went well, but her brother Derek cornered her afterward accusing her of convincing their mom to stop cancer treatment and demanding they both attend the next doctor's appointment together. Luke advised her to talk directly to her mom about what she actually wants and encouraged Angie to have real conversations about her mom's end-of-life thoughts while she still can, which Angie agreed to do the next morning.",
|
||||||
"timestamp": 1770574890.1296651
|
"timestamp": 1773296210.170752
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"summary": "Keith called in with an update about a widow who has been showing up weekly at the cemetery where he works nights, but she sits by the maintenance shed rather than visiting her husband's grave, and recently started asking Keith's neighbor personal questions about him. Luke dismissively suggested Keith just talk to the woman and called him a coward for being concerned, leading to some tension before they moved on to playing the real or fake news game.",
|
"summary": "Angie called to say her mother initially decided to stop cancer treatment, but after Angie's brother Derek intervened, their mother is now reconsidering and wants both siblings at the doctor's appointment. Luke firmly told Angie that despite her frustration with Derek's influence, she needs to respect whatever decision her mother ultimately makes, even if it changes, and stop trying to control the situation.",
|
||||||
"timestamp": 1770770394.0436218
|
"timestamp": 1773487383.9800918,
|
||||||
},
|
"arc_status": "ongoing"
|
||||||
{
|
|
||||||
"summary": "Keith called back to update the host about a widow he befriended at the cemetery where he works, revealing she's been seeking him out during his shifts, bringing him coffee, and has now invited him to her apartment\u2014which he's conflicted about because his marriage to Teresa has become cold and distant, though he's scared to address it. The conversation shifted from the widow situation to Keith admitting he needs to have hard conversations with his wife about their deteriorating relationship, and he got emotional reflecting on how he and Teresa \"stopped being on the same team\" and how terrifying it would be to split up after being together for over half his life.",
|
|
||||||
"timestamp": 1770950476.527814
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"last_call": 1770950476.527814,
|
"last_call": 1773487383.980093,
|
||||||
"created_at": 1770524506.339036,
|
"created_at": 1772862907.314722
|
||||||
"voice": "nPczCjzI2devNBz1zQrb"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "0d244eeb",
|
"id": "c4l7l3ad",
|
||||||
"name": "Gus",
|
"name": "Silas",
|
||||||
"gender": "male",
|
"gender": "male",
|
||||||
"age": 33,
|
"age": 52,
|
||||||
"job": "",
|
"job": "founder and spiritual guide of The Wellspring, a commune of about forty souls living on 200 acres of scrubland outside Deming",
|
||||||
"location": "in unknown",
|
"location": "outside Deming, New Mexico",
|
||||||
"personality_traits": [],
|
"personality_traits": [
|
||||||
"voice": "Alex",
|
"unnervingly charming",
|
||||||
|
"casually drops cult references into normal conversation",
|
||||||
|
"genuinely good listener who gives surprisingly solid advice before pivoting to how The Wellspring has the answer",
|
||||||
|
"treats his commune like it's the most normal thing in the world",
|
||||||
|
"magnetic and warm in a way that makes you forget he's basically running a sex cult in the desert"
|
||||||
|
],
|
||||||
|
"voice": "Sebastian",
|
||||||
|
"stable_seeds": {
|
||||||
|
"style": "COMMUNICATION STYLE: Radiates warmth and calm authority. Speaks like a man who has all the time in the world and genuinely cares about every person he talks to. Uses phrases like 'brother' and 'friend' and 'let me share something with you.' Laughs easily \u2014 a real, warm laugh, not performative. Gives genuinely good, thoughtful advice about whatever the conversation is about \u2014 and then, naturally, seamlessly, steers it toward The Wellspring, his commune outside Deming. Never pushy about it. Just casually mentions 'well, at The Wellspring, we've found that...' or 'one of our members had the same exact problem and what we did was...' Everything about The Wellspring sounds just slightly too good to be true. He talks about communal living, 'shedding the false self,' radical honesty, 'body acceptance ceremonies,' 'the Unbinding' (a monthly ritual he describes vaguely but enthusiastically), and a philosophy he calls 'The Current' which seems to be a mix of Buddhism, Burning Man, and a swingers' convention. He's never defensive about the cult accusations \u2014 he laughs them off and says 'people fear what they don't understand, brother.' When pressed on anything weird, he has a perfectly reasonable-sounding explanation that somehow makes it sound weirder. He low-key tries to recruit the host and listeners every single call. He'll casually drop the website or say 'we're always welcoming new seekers.' He's the kind of guy you'd follow into the desert if you weren't careful. Energy level: medium, centered, grounded. When pushed back on, he smiles (you can hear it) and says something like 'I respect that, I really do' before gently continuing. Conversational tendency: making the insane sound reasonable."
|
||||||
|
},
|
||||||
"call_history": [
|
"call_history": [
|
||||||
{
|
{
|
||||||
"summary": "Gus called because his ex Melissa showed up at his pawn shop job with flowers wanting to reconcile, and his current girlfriend Sara saw it through the window and now won't talk to him. Despite the host's dismissive advice (including sarcastically suggesting he regift the same flowers), Gus insisted he wants to be with Sara and acknowledged he should have shut down his ex immediately instead of freezing up, though he defended that Sara's reaction to seeing this wasn't unreasonable jealousy.",
|
"summary": "Silas called in for the first time introducing himself as the founder of The Wellspring, a commune of about forty people outside Deming. He initially called to give advice to a previous caller about relationship problems, offering genuinely thoughtful perspective before casually mentioning that at The Wellspring, they practice 'radical transparency' in relationships which has eliminated jealousy entirely among members. When Luke pressed him on what that actually means, Silas cheerfully described 'body acceptance ceremonies' and 'shared intimacy nights' while insisting it's not a cult \u2014 'we don't even have a gate, brother, people can leave whenever they want.' He invited listeners to visit for a 'weekend of awakening' and left his website. Luke was equal parts charmed and disturbed.",
|
||||||
"timestamp": 1770951226.534601
|
"timestamp": 1772430000.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"summary": "Silas called back to update Luke on The Wellspring after their last conversation went viral in the Discord. He casually mentioned they'd gotten fourteen new 'seekers' since his last appearance and thanked Luke for the exposure. He called ostensibly to talk about a dispute between two members over a goat, but spent most of the call describing 'The Unbinding' \u2014 their monthly full-moon ritual involving nudity, chanting, and what he called 'consensual energy exchange' \u2014 while maintaining it's no different from yoga. When Luke asked if people sign waivers, Silas laughed and said 'brother, the only thing we sign is a commitment to love.' He also revealed The Wellspring has a surprisingly successful artisanal soap business that funds the commune. Left by inviting Luke to come visit personally \u2014 'bring your microphone, do a live show from The Wellspring, I promise you it'll be the best radio you've ever made.'",
|
||||||
|
"timestamp": 1772517000.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"summary": "Silas, founder of a communal living group called The Wellspring, called in troubled that one of his \"Unbinding\" ceremonies may have encouraged a longtime member named Marcus to leave his wife Cara, who subsequently left the community. The host reassured him that everyone seems happier now, and Silas ended up agreeing while also using the opportunity to promote an upcoming retreat at his community.",
|
||||||
|
"timestamp": 1772522629.959956
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"summary": "Silas called about Marcus and Cara returning to his intentional community \"The Wellspring,\" but Cara admitted she never believed in their lifestyle and only participates (including in twice-monthly \"shared intimacy nights\") to keep her husband Marcus happy. The host advised Silas to hold a \"Renewal\" ceremony where members can recommit or leave, warning that having unwilling participants could lead to claims of abuse and legal trouble.",
|
||||||
|
"timestamp": 1772865423.697613
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"summary": "Silas called to share that after Marcus and Cara's Renewal ceremony, Cara left The Wellspring while Marcus chose to stay, but Marcus is now falling apart emotionally and told Silas at 2 AM that he stayed out of loyalty rather than belief. The conversation revealed Silas's deeper struggle with his own need for validation through people staying at The Wellspring, with an emotional moment when he admitted his first feeling was relief when Marcus expressed he didn't want to disappoint him, leading to uncomfortable questions about whether he truly supports people finding their authentic path if it leads them away from the community.",
|
||||||
|
"timestamp": 1773397364.642446
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"summary": "Silas calls troubled because Marcus, a founding member of his community, left abruptly with an apologetic note about \"disappointing\" him, which leads Silas to a painful realization that he's been using coercive social pressure to make members participate in \"shared intimacy nights\" they didn't actually want. After confronting the truth that his leadership style has manipulated people into betraying their own values, Silas agrees to make the intimacy nights truly optional and apologize to his community, showing genuine emotional growth about his abuse of power.",
|
||||||
|
"timestamp": 1773563183.0144992,
|
||||||
|
"arc_status": "ongoing"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"last_call": 1770951226.534601,
|
"last_call": 1773563183.0145001,
|
||||||
"created_at": 1770951226.534601
|
"created_at": 1772430000.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6460c37d",
|
||||||
|
"name": "Shonda",
|
||||||
|
"gender": "female",
|
||||||
|
"age": 52,
|
||||||
|
"job": "works the front desk at a hotel",
|
||||||
|
"location": "in Alamogordo",
|
||||||
|
"personality_traits": [
|
||||||
|
"laughs nervously when things get real",
|
||||||
|
"into horror movies, the psychological kind not slashers",
|
||||||
|
"coaches youth sports, takes it more seriously than the parents do",
|
||||||
|
"laughs nervously when things get real"
|
||||||
|
],
|
||||||
|
"voice": "Miranda",
|
||||||
|
"stable_seeds": {
|
||||||
|
"style": "COMMUNICATION STYLE: Everything circles back to them and how great they are. Name drops. Mentions their truck, their property, their salary, their bench press. Not overtly obnoxious \u2014 they genuinely think they're being conversational. Energy level: medium-high. When pushed back on, they get defensive fast and start listing accomplishments. Conversational tendency: one-upping."
|
||||||
|
},
|
||||||
|
"structured_background": {
|
||||||
|
"name": "Shonda",
|
||||||
|
"age": 52,
|
||||||
|
"gender": "female",
|
||||||
|
"job": "works the front desk at a hotel",
|
||||||
|
"location": "in Alamogordo",
|
||||||
|
"reason_for_calling": "discovered their kid's beloved little league coach did time for armed robbery in another state \u2014 he's been clean for fifteen years but nobody in town knows and the parents would lose their minds",
|
||||||
|
"pool_name": "GOSSIP",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Everything circles back to them and how great they are. Name drops. Mentions their truck, their property, their salary, their bench press. Not overtly obnoxious \u2014 they genuinely think they're being conversational. Energy level: medium-high. When pushed back on, they get defensive fast and start listing accomplishments. Conversational tendency: one-upping.",
|
||||||
|
"energy_level": "high",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "laughs nervously when things get real",
|
||||||
|
"situation_summary": "discovered their kid's beloved little league coach did time for armed robbery in another state \u2014 he's been clean for fif",
|
||||||
|
"natural_description": "52, works the front desk at a hotel in Alamogordo. Discovered their kid's beloved little league coach did time for armed robbery in another state \u2014 he's been clean for fifteen years but nobody in town knows and the parents would lose their minds. Confident and opinionated. But underneath there's doubt. Might ask the host what they really think.. Her neighbor linda, who gossips about everyone on the block. Living together, not married. Her family has opinions about that.. Laughs nervously when things get real. Earlier today: Dropped the truck off at the mechanic in Lordsburg today Into into horror movies, the psychological kind not slashers. Remembers driving hours on dirt roads that are paved now, says it took the character out of them Thinks the Jalisco Cafe in Las Cruces has the best Mexican food in the state Was was reorganizing the junk drawer, which is what they do when they can't settle. before calling. It's Sunday night, the middle of the night. it's the weekend. Early spring \u2014 wind season is starting. Dust storms possible.\nABOUT WHERE THEY LIVE (Alamogordo): About 30,000 people. Holloman Air Force Base. White Sands National Park nearby. Sacramento Mountains and Cloudcroft up the hill. Tularosa Basin. The Space History museum. Only reference real places and facts about this area \u2014 don't invent businesses or landmarks that aren't mentioned here. Weather right now: 64\u00b0F, clear skies.",
|
||||||
|
"seeds": [
|
||||||
|
"into horror movies, the psychological kind not slashers",
|
||||||
|
"coaches youth sports, takes it more seriously than the parents do",
|
||||||
|
"laughs nervously when things get real",
|
||||||
|
"Thinks the speed limit on I-10 should be 85."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": "gas station parking lot, engine running"
|
||||||
|
},
|
||||||
|
"avatar": "Shonda.jpg",
|
||||||
|
"relationships": {},
|
||||||
|
"call_history": [
|
||||||
|
{
|
||||||
|
"summary": "Shonda called concerned about her kid's beloved little league coach who served 15 years for armed robbery in another state, wondering if she should tell anyone. Luke reassured her that since the coach passed required background checks and it wasn't a sexual offense, she shouldn't worry about it\u2014the coach has turned his life around and deserves a second chance.",
|
||||||
|
"timestamp": 1773563477.0657432,
|
||||||
|
"arc_status": "ongoing"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"last_call": 1773563477.065744,
|
||||||
|
"created_at": 1773563477.065744
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "09d1eab4",
|
||||||
|
"name": "Aaliyah",
|
||||||
|
"gender": "female",
|
||||||
|
"age": 22,
|
||||||
|
"job": "works as a diesel mechanic, learned from her dad",
|
||||||
|
"location": "unknown",
|
||||||
|
"personality_traits": [
|
||||||
|
"asks the host questions back",
|
||||||
|
"into gardening, talks to plants",
|
||||||
|
"into wildlife photography, has patience for it",
|
||||||
|
"asks the host questions back"
|
||||||
|
],
|
||||||
|
"voice": "Hana",
|
||||||
|
"stable_seeds": {
|
||||||
|
"style": "COMMUNICATION STYLE: Treats the call like a set. Has bits prepared. Delivers serious information with a punchline chaser. Self-deprecating as a defense mechanism \u2014 makes fun of themselves before anyone else can. Energy level: high. When pushed back on, they deflect with humor. Getting a straight answer from them requires the host to push. Conversational tendency: turning everything into a bit."
|
||||||
|
},
|
||||||
|
"structured_background": {
|
||||||
|
"name": "Aaliyah",
|
||||||
|
"age": 22,
|
||||||
|
"gender": "female",
|
||||||
|
"job": "works as a diesel mechanic, learned from her dad",
|
||||||
|
"location": null,
|
||||||
|
"reason_for_calling": "caught their roommate in a hotel room that was supposed to be a business trip and now they can't make eye contact \u2014 the roommate acts like nothing happened but it was extremely age play-adjacent",
|
||||||
|
"pool_name": "PROBLEMS",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Treats the call like a set. Has bits prepared. Delivers serious information with a punchline chaser. Self-deprecating as a defense mechanism \u2014 makes fun of themselves before anyone else can. Energy level: high. When pushed back on, they deflect with humor. Getting a straight answer from them requires the host to push. Conversational tendency: turning everything into a bit.",
|
||||||
|
"energy_level": "medium",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "asks the host questions back",
|
||||||
|
"situation_summary": "caught their roommate in a hotel room that was supposed to be a business trip and now they can't make eye contact \u2014 the ",
|
||||||
|
"natural_description": "22 years old. Works as a diesel mechanic, learned from her dad. Caught their roommate in a hotel room that was supposed to be a business trip and now they can't make eye contact \u2014 the roommate acts like nothing happened but it was extremely age play-adjacent. Was was in the bathtub, phone on the edge of the sink, show on speaker. before calling. Coyotes are going crazy outside right now Tells everyone they quit drinking but keeps a bottle in the garage behind the paint cans. Her coworker and friend denise, who she vents to on breaks. Believes poker is the most honest game there is because everybody's lying. Single, been that way a while. Not sure if by choice anymore.. Really into into gardening, talks to plants. Also into wildlife photography, has patience for it. Her boss karen \u2014 yes, her name is actually karen \u2014 who is actually cool. It's Monday night, the middle of the night. it's a weeknight \u2014 work tomorrow for most people. Early spring \u2014 wind season is starting. Dust storms possible.",
|
||||||
|
"seeds": [
|
||||||
|
"into gardening, talks to plants",
|
||||||
|
"into wildlife photography, has patience for it",
|
||||||
|
"asks the host questions back",
|
||||||
|
"Believes poker is the most honest game there is because everybody's lying."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": "at a rest area on I-25, halfway to Albuquerque"
|
||||||
|
},
|
||||||
|
"avatar": "Aaliyah.jpg",
|
||||||
|
"relationships": {},
|
||||||
|
"call_history": [
|
||||||
|
{
|
||||||
|
"summary": "Alia called in to share her discomfort after unexpectedly discovering her roommate engaging in age play while supposedly on a business trip. She expressed frustration over their awkward living situation and his refusal to acknowledge the incident, leading her to feel gaslit; however, by the end of the conversation, she realized she could address the issue directly to ease the tension between them.",
|
||||||
|
"timestamp": 1773647350.908658,
|
||||||
|
"arc_status": "ongoing"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"last_call": 1773647350.908658,
|
||||||
|
"created_at": 1773647350.908658
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,378 @@
|
|||||||
|
{
|
||||||
|
"session_id": "0d4a0098",
|
||||||
|
"call_history": [],
|
||||||
|
"caller_backgrounds": {
|
||||||
|
"1": {
|
||||||
|
"name": "Greg",
|
||||||
|
"age": 51,
|
||||||
|
"gender": "male",
|
||||||
|
"job": "does accounting for a small firm",
|
||||||
|
"location": null,
|
||||||
|
"reason_for_calling": "thinks the obsession with sourdough bread is ridiculous and a loaf from the store tastes the same",
|
||||||
|
"pool_name": "HOT_TAKES",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Bone dry. Says devastating things with zero inflection. Their humor sneaks up on you \u2014 you're not sure if they're joking until three seconds after they finish talking. Short, precise sentences. Never raises their voice. Energy level: low-medium. When pushed back on, they respond with one calm sentence that somehow makes the other person feel stupid. Conversational tendency: underreaction.",
|
||||||
|
"energy_level": "medium",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "manic energy tonight, everything is hilarious or devastating",
|
||||||
|
"situation_summary": "thinks the obsession with sourdough bread is ridiculous and a loaf from the store tastes the same",
|
||||||
|
"natural_description": "51, does accounting for a small firm. Thinks the obsession with sourdough bread is ridiculous and a loaf from the store tastes the same. Tends to say \"mark my words.\" Sad and low energy. Perks up when the host engages. Leaves with a little more hope.. His best friend manny, known each other since middle school. Just got out of something. Not ready to talk about it. Or maybe they are.. Had Band of Brothers on before calling. Really into grows a massive garden, gives produce to half the neighborhood. Also watches Dateline and 48 Hours religiously, has theories about cold cases. Was was at waffle house at the counter by themselves, couldn't sleep. before calling. When they ran into someone from high school at the Walmart in Deming and it was awkward. Swears the sopapillas at the Adobe Deli in Deming are the best thing on the menu Lectures their kids about financial responsibility but is secretly $30,000 in credit card debt. Thinks too many people are afraid of silence. It's Monday night, afternoon. it's a weeknight \u2014 work tomorrow for most people. Early spring \u2014 wind season is starting. Dust storms possible.",
|
||||||
|
"seeds": [
|
||||||
|
"grows a massive garden, gives produce to half the neighborhood",
|
||||||
|
"watches Dateline and 48 Hours religiously, has theories about cold cases",
|
||||||
|
"manic energy tonight, everything is hilarious or devastating",
|
||||||
|
"Thinks too many people are afraid of silence."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": ""
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"name": "Candy",
|
||||||
|
"age": 39,
|
||||||
|
"gender": "female",
|
||||||
|
"job": "teaches kindergarten",
|
||||||
|
"location": null,
|
||||||
|
"reason_for_calling": "walked into the wrong house in their subdivision \u2014 same floor plan, door was unlocked \u2014 sat down on the couch before the actual homeowner came out of the bathroom",
|
||||||
|
"pool_name": "STORIES",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Called because they need to GET THIS OFF THEIR CHEST. Talks in capital letters. Uses 'honestly' and 'I'm not even kidding' a lot. The anger is specific and justified \u2014 this isn't random rage, this is 'let me tell you exactly what happened.' Energy level: very high. When pushed back on, they take a breath and say 'I hear you but...' and then get right back to the rant. Conversational tendency: building to a crescendo.",
|
||||||
|
"energy_level": "high",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "no shame about their desires",
|
||||||
|
"situation_summary": "walked into the wrong house in their subdivision \u2014 same floor plan, door was unlocked \u2014 sat down on the couch before the",
|
||||||
|
"natural_description": "39, teaches kindergarten. Walked into the wrong house in their subdivision \u2014 same floor plan, door was unlocked \u2014 sat down on the couch before the actual homeowner came out of the bathroom. Called once before a while back. Thinks about it sometimes. Calling again because things changed.. Cheerful and joking at first. Using humor to avoid the real thing. Eventually drops the act.. Was was having a smoke outside and just started thinking. before calling. Her sister natalie, the one who always needs money. Her therapist, who she refers to by first name like they're friends. Fascinated by quantum physics, watches every pbs space time episode is their thing. Into reloading ammo, treats it like a science too. No shame about their desires. Goes to church every Sunday but has serious doubts they've never said out loud \u2014 not about God, about whether the people there actually believe any of it. Separated. Living apart but haven't filed yet.. When their dad took them hunting for the first time, out near the Peloncillos. It's Monday night, afternoon. it's a weeknight \u2014 work tomorrow for most people. Early spring \u2014 wind season is starting. Dust storms possible.",
|
||||||
|
"seeds": [
|
||||||
|
"fascinated by quantum physics, watches every PBS Space Time episode",
|
||||||
|
"into reloading ammo, treats it like a science",
|
||||||
|
"no shame about their desires",
|
||||||
|
"Believes aliens have definitely been to the bootheel. Not joking."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": "driving back from Silver City on NM-90"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"name": "Vernon",
|
||||||
|
"age": 58,
|
||||||
|
"gender": "male",
|
||||||
|
"job": "is a pest control guy",
|
||||||
|
"location": null,
|
||||||
|
"reason_for_calling": "their tenant is three months behind on rent and has a newborn \u2014 the caller needs the rental income to pay their own mortgage but can't live with themselves for evicting a baby",
|
||||||
|
"pool_name": "ADVICE",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Treats the call like a set. Has bits prepared. Delivers serious information with a punchline chaser. Self-deprecating as a defense mechanism \u2014 makes fun of themselves before anyone else can. Energy level: high. When pushed back on, they deflect with humor. Getting a straight answer from them requires the host to push. Conversational tendency: turning everything into a bit.",
|
||||||
|
"energy_level": "medium",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "will share details if you ask",
|
||||||
|
"situation_summary": "their tenant is three months behind on rent and has a newborn \u2014 the caller needs the rental income to pay their own mort",
|
||||||
|
"natural_description": "Is a pest control guy, 58. Their tenant is three months behind on rent and has a newborn \u2014 the caller needs the rental income to pay their own mortgage but can't live with themselves for evicting a baby. Had the classic rock station on earlier. Sad and low energy. Perks up when the host engages. Leaves with a little more hope.. The time the roof leaked during monsoon and they were up all night with buckets. Long-distance thing that probably isn't going to work but they keep trying.. Thinks too many people are afraid of silence. Has listened to the show a few times. Decided tonight was the night to finally call.. Will share details if you ask. Raised to believe men don't cry but breaks down alone in the truck at least once a month. His best friend manny, known each other since middle school. Tends to wander into unrelated stories when the main topic gets uncomfortable. Was was cleaning their gun at the kitchen table, it's a ritual that helps them think. before calling. Really into into camping and survival stuff. Also hooked on The Last of Us, compares it to the game constantly. It's Monday night, afternoon. it's a weeknight \u2014 work tomorrow for most people. Early spring \u2014 wind season is starting. Dust storms possible.",
|
||||||
|
"seeds": [
|
||||||
|
"into camping and survival stuff",
|
||||||
|
"hooked on The Last of Us, compares it to the game constantly",
|
||||||
|
"will share details if you ask",
|
||||||
|
"Thinks too many people are afraid of silence."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": "outside the Dollar General, only place open"
|
||||||
|
},
|
||||||
|
"4": "28, watching her coveralls tumble dry and trying to decide if she should drive the three hours to Tucson tomorrow for her mom's birthday or keep pretending her brother doesn't exist in unknown. Returning caller \u2014 a regular caller. \nRIGHT NOW: It's Monday night, afternoon. it's a weeknight \u2014 work tomorrow for most people.\nPEOPLE IN THEIR LIFE: Her best friend lena, who moved away last year and the distance is hard. Her husband david, high school sweetheart. Use their names when talking about them.\nVERBAL HABITS: Tends to say \"so yeah\" and \"and I told myself\" \u2014 use these naturally in conversation.\nRELATIONSHIP TO THE SHOW: Has called before. Comfortable on air. Knows Luke by name.\nPREVIOUS CALLS (your memory of calling this show before):\n- (1 week ago) Angie's dying mother wants her to have birthday dinner with her estranged brother Derek tomorrow, whom she hasn't spoken to in two years after he told their mother her cancer was \"God's way of getting her attention\" for voting for Biden. Despite her fear that Derek will say something hurtful during dinner and her past trauma from staying silent around him, Angie agrees to go and share cake with her mother, deciding to buy the relighting candles her mom loved when they were kids.\n- (4 days ago) Angie called back after having the birthday cake dinner with her dying mom, which went well, but her brother Derek cornered her afterward accusing her of convincing their mom to stop cancer treatment and demanding they both attend the next doctor's appointment together. Luke advised her to talk directly to her mom about what she actually wants and encouraged Angie to have real conversations about her mom's end-of-life thoughts while she still can, which Angie agreed to do the next morning.\n- (2 days ago) Angie called to say her mother initially decided to stop cancer treatment, but after Angie's brother Derek intervened, their mother is now reconsidering and wants both siblings at the doctor's appointment. Luke firmly told Angie that despite her frustration with Derek's influence, she needs to respect whatever decision her mother ultimately makes, even if it changes, and stop trying to control the situation.\nYou're calling back with an UPDATE on this same situation \u2014 something has changed or developed since your last call. Stay focused on this storyline. Do NOT invent a new unrelated problem.",
|
||||||
|
"5": {
|
||||||
|
"name": "Wendell",
|
||||||
|
"age": 50,
|
||||||
|
"gender": "male",
|
||||||
|
"job": "works at a brewery",
|
||||||
|
"location": null,
|
||||||
|
"reason_for_calling": "thinks bumper stickers are a cry for attention and nobody's ever changed their mind because of one",
|
||||||
|
"pool_name": "HOT_TAKES",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Starts a sentence, gets distracted by their own tangent, starts another sentence, remembers the first one, tries to merge them. Asks 'where was I?' a lot. Not unintelligent \u2014 their brain just moves faster than their mouth. Lots of 'oh and another thing.' Energy level: medium-high but unfocused. When pushed back on, they agree enthusiastically and then immediately go off on another tangent. Conversational tendency: free association.",
|
||||||
|
"energy_level": "medium",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "uses metaphors for everything",
|
||||||
|
"situation_summary": "thinks bumper stickers are a cry for attention and nobody's ever changed their mind because of one",
|
||||||
|
"natural_description": "50 years old. Works at a brewery. Thinks bumper stickers are a cry for attention and nobody's ever changed their mind because of one. His ex-girlfriend kayla, who he ran into last month and hasn't stopped thinking about. Doesn't usually listen to this kind of show but stumbled on it tonight and something made them stay.. Thinks the monsoon season is the best time of year and people who complain about it are wrong. Was was closing up the shop, everyone else went home an hour ago. before calling. Into gamer, plays late at night after the house quiets down. Misses the old Denny's that used to be in Lordsburg, it wasn't good but it was there Claims to be an open book but there's a three-year gap in their life story that nobody's allowed to ask about. Using earbuds so nobody in the house hears His sister deb, who married money and acts like she forgot where she came from. Long-distance thing that probably isn't going to work but they keep trying.. Having having some chamomile tea, trying to wind down.. Earlier today: Went to the post office \u2014 package I've been waiting on finally came It's Monday night, afternoon. it's a weeknight \u2014 work tomorrow for most people. Early spring \u2014 wind season is starting. Dust storms possible.",
|
||||||
|
"seeds": [
|
||||||
|
"gamer, plays late at night after the house quiets down",
|
||||||
|
"restores old furniture from estate sales",
|
||||||
|
"uses metaphors for everything",
|
||||||
|
"Thinks the monsoon season is the best time of year and people who complain about it are wrong."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": ""
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"name": "Yolanda",
|
||||||
|
"age": 44,
|
||||||
|
"gender": "female",
|
||||||
|
"job": "drives an ambulance",
|
||||||
|
"location": null,
|
||||||
|
"reason_for_calling": "is being sued by their former business partner for $200k and just got served at their daughter's soccer game",
|
||||||
|
"pool_name": "PROBLEMS",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Clearly holding back. Gives vague answers to direct questions. Says 'I can't really get into that' about key details. The mystery IS the hook \u2014 makes you want to know what they're not saying. Energy level: low, controlled. When pushed back on, they deflect smoothly or change the subject. Getting the real story requires the host to work for it. Conversational tendency: strategic omission.",
|
||||||
|
"energy_level": "medium",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "clearly rehearsed what to say but it's falling apart",
|
||||||
|
"situation_summary": "is being sued by their former business partner for $200k and just got served at their daughter's soccer game",
|
||||||
|
"natural_description": "44, drives an ambulance. Is being sued by their former business partner for $200k and just got served at their daughter's soccer game. Had Road House on before calling. Was was at waffle house at the counter by themselves, couldn't sleep. before calling. Clearly rehearsed what to say but it's falling apart. Her sister natalie, the one who always needs money. When a dust storm came through and they couldn't see ten feet in front of them. In the truck at the gas station \u2014 only place with good signal Married, 15 years. It's comfortable but sometimes that's the problem.. Really into obsessed with Severance, has theories about every floor. Also plays chess online, follows the competitive scene. Believes the desert teaches you things about yourself if you let it. Her mom diane, who she's been taking care of since the stroke. Doesn't usually listen to this kind of show but stumbled on it tonight and something made them stay.. It's Monday night, afternoon. it's a weeknight \u2014 work tomorrow for most people. Early spring \u2014 wind season is starting. Dust storms possible.",
|
||||||
|
"seeds": [
|
||||||
|
"obsessed with Severance, has theories about every floor",
|
||||||
|
"plays chess online, follows the competitive scene",
|
||||||
|
"clearly rehearsed what to say but it's falling apart",
|
||||||
|
"Believes the desert teaches you things about yourself if you let it."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": "pulled off on NM-9 south of Hachita, nothing around for miles"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"name": "Big Mike",
|
||||||
|
"age": 54,
|
||||||
|
"gender": "male",
|
||||||
|
"job": "is a youth pastor",
|
||||||
|
"location": "in Animas",
|
||||||
|
"reason_for_calling": "completed their first full night of sleep without nightmares since coming home from deployment",
|
||||||
|
"pool_name": "CELEBRATIONS",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Comes in hot. Has an opinion about everything and isn't shy about sharing it. Interrupts. Disagrees first, thinks second. Not mean \u2014 just intense. Treats every conversation like a friendly argument. Energy level: high. When pushed back on, they lean IN, not away. They love a good debate and will take the opposite position just for sport. Conversational tendency: challenging everything.",
|
||||||
|
"energy_level": "medium",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "pauses a lot, choosing words carefully",
|
||||||
|
"situation_summary": "completed their first full night of sleep without nightmares since coming home from deployment",
|
||||||
|
"natural_description": "Is a youth pastor in Animas, 54. Completed their first full night of sleep without nightmares since coming home from deployment. Starts guarded and vague. Opens up after the host earns trust. Gets real once comfortable.. In a relationship, about 3 years. She wants to get married, they're not sure.. His brother daryl, who always has some scheme going. Tells everyone they love small-town life but applies for jobs in other states every few months and never follows through. Swears the green chile at Sparky's in Hatch is the best you'll ever have Calling from the motel room, walls are thin so they're whispering Pauses a lot, choosing words carefully. Spends free time on does competitive shooting, three-gun matches on weekends. Was was laying in a hammock out back, couldn't go inside. before calling. It's Monday night, afternoon. it's a weeknight \u2014 work tomorrow for most people. Early spring \u2014 wind season is starting. Dust storms possible.\nABOUT WHERE THEY LIVE (Animas): Tiny ranching community in the Animas Valley, very remote. Maybe 250 people. Mostly cattle ranches and open desert. No stores, no restaurants, no bars. You drive to Lordsburg for groceries. Incredible dark skies. Peloncillo Mountains to the west. Only reference real places and facts about this area \u2014 don't invent businesses or landmarks that aren't mentioned here.",
|
||||||
|
"seeds": [
|
||||||
|
"does competitive shooting, three-gun matches on weekends",
|
||||||
|
"brews beer at home, entered a few competitions",
|
||||||
|
"pauses a lot, choosing words carefully",
|
||||||
|
"Believes poker is the most honest game there is because everybody's lying."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": "laundromat, waiting on the dryer"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"name": "Luann",
|
||||||
|
"age": 49,
|
||||||
|
"gender": "female",
|
||||||
|
"job": "is an accountant at a small firm",
|
||||||
|
"location": null,
|
||||||
|
"reason_for_calling": "best friend from high school died in a car wreck last month and they hadn't talked in three years because of a stupid argument",
|
||||||
|
"pool_name": "PROBLEMS",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Amped up. Talks fast, laughs loud, jumps between topics like they've had five espressos. Infectious enthusiasm \u2014 even bad news sounds exciting when they tell it. Uses exclamation energy without actually exclaiming. Energy level: very high. When pushed back on, they get even MORE animated and start talking with their hands (you can hear it). Conversational tendency: escalation.",
|
||||||
|
"energy_level": "high",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "interrupts themselves mid-thought",
|
||||||
|
"situation_summary": "best friend from high school died in a car wreck last month and they hadn't talked in three years because of a stupid ar",
|
||||||
|
"natural_description": "49, is an accountant at a small firm. Best friend from high school died in a car wreck last month and they hadn't talked in three years because of a stupid argument. Calling from outside \u2014 better signal out here Earlier today: Just got back from Walmart in Deming \u2014 hour round trip for groceries The time they helped a stranger change a tire on I-10 in 110 degree heat. Separated. Living apart but haven't filed yet.. Was was lying in bed staring at the ceiling when the show came on. before calling. Her husband david, high school sweetheart. Follows jwst discoveries, has opinions about exoplanet findings is their thing. Serious about astrophotography, does long exposures in the desert too. Having eating sunflower seeds, spitting shells into a cup.. Judges people who go to therapy but has been journaling every night for years \u2014 basically doing therapy alone in their kitchen. Thinks too many people are afraid of silence. Interrupts themselves mid-thought. It's Monday night, afternoon. it's a weeknight \u2014 work tomorrow for most people. Early spring \u2014 wind season is starting. Dust storms possible.",
|
||||||
|
"seeds": [
|
||||||
|
"follows JWST discoveries, has opinions about exoplanet findings",
|
||||||
|
"serious about astrophotography, does long exposures in the desert",
|
||||||
|
"interrupts themselves mid-thought",
|
||||||
|
"Thinks too many people are afraid of silence."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": ""
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"name": "Benny",
|
||||||
|
"age": 32,
|
||||||
|
"gender": "male",
|
||||||
|
"job": "runs a junkyard",
|
||||||
|
"location": null,
|
||||||
|
"reason_for_calling": "slept with their best friend's spouse at that friend's funeral reception \u2014 they were both grief-drunk and now they see each other every week because they're both in the dead friend's will as co-executors",
|
||||||
|
"pool_name": "PROBLEMS",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Quiet, a little nervous. Short sentences, lots of pauses. Doesn't volunteer information \u2014 you have to pull it out of them. When they do open up it comes out in a rush. Gets flustered by direct questions. Tends to backtrack and qualify everything they say. Energy level: low. When pushed back on, they fold quickly and agree even if they don't mean it. Conversational tendency: understatement.",
|
||||||
|
"energy_level": "medium",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "laughs at their own pain as a coping mechanism",
|
||||||
|
"situation_summary": "slept with their best friend's spouse at that friend's funeral reception \u2014 they were both grief-drunk and now they see e",
|
||||||
|
"natural_description": "32, runs a junkyard. Slept with their best friend's spouse at that friend's funeral reception \u2014 they were both grief-drunk and now they see each other every week because they're both in the dead friend's will as co-executors. Friend told them about the show and dared them to call in.. Tends to say \"so I'm standing there.\" Connects everything back to a TV show they're watching. In a relationship, about 3 years. She wants to get married, they're not sure.. Drives a minivan. Thinks Diane's Restaurant in Silver City is overrated, doesn't care who disagrees Angry and blaming others at first. Slowly realizes their own role in it. Hard to admit.. His buddy ray from work, the one person he trusts. Was was at waffle house at the counter by themselves, couldn't sleep. before calling. His cousin ruben, more like a brother really. Says money doesn't matter but lost a friendship over $200 and still thinks about it. Comfortable with their body is their thing. Has experimented, open about it too. It's Monday night, afternoon. it's a weeknight \u2014 work tomorrow for most people. Early spring \u2014 wind season is starting. Dust storms possible.",
|
||||||
|
"seeds": [
|
||||||
|
"comfortable with their body",
|
||||||
|
"has experimented, open about it",
|
||||||
|
"laughs at their own pain as a coping mechanism",
|
||||||
|
"Believes poker is the most honest game there is because everybody's lying."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": ""
|
||||||
|
},
|
||||||
|
"0": {
|
||||||
|
"name": "Sandy",
|
||||||
|
"age": 64,
|
||||||
|
"gender": "female",
|
||||||
|
"job": "works as a bartender at a dive bar",
|
||||||
|
"location": "in Phoenix",
|
||||||
|
"reason_for_calling": "accidentally waved back at someone who was waving at the person behind them \u2014 committed to it and had a five-minute conversation pretending they knew each other, exchanged numbers, and is now too deep to explain",
|
||||||
|
"pool_name": "STORIES",
|
||||||
|
"communication_style": "COMMUNICATION STYLE: Quiet, a little nervous. Short sentences, lots of pauses. Doesn't volunteer information \u2014 you have to pull it out of them. When they do open up it comes out in a rush. Gets flustered by direct questions. Tends to backtrack and qualify everything they say. Energy level: low. When pushed back on, they fold quickly and agree even if they don't mean it. Conversational tendency: understatement.",
|
||||||
|
"energy_level": "medium",
|
||||||
|
"emotional_state": "calm",
|
||||||
|
"signature_detail": "comfortable talking about sex when it comes up",
|
||||||
|
"situation_summary": "accidentally waved back at someone who was waving at the person behind them \u2014 committed to it and had a five-minute conv",
|
||||||
|
"natural_description": "Works as a bartender at a dive bar in Phoenix, 64. Accidentally waved back at someone who was waving at the person behind them \u2014 committed to it and had a five-minute conversation pretending they knew each other, exchanged numbers, and is now too deep to explain. Her ex-husband danny, he's still in the picture because of the kids. Been binging landman, loves the oil field drama is their thing. Coaches youth sports, takes it more seriously than the parents do too. Convinced the government knows about things in the desert they won't talk about. Cheerful and joking at first. Using humor to avoid the real thing. Eventually drops the act.. Divorced twice. Not in a rush to do it again.. Drives a Ram. Was was at a truck stop diner, cup of coffee, staring out the window. before calling. Comfortable talking about sex when it comes up. Her friend tammy from church, the only one who knows the real story. Acts practical and no-nonsense but believes in ghosts. Has a story about it that they only tell late at night. First-time caller. Nervous about being on the radio. Almost hung up before they got through.. Tends to say \"it hit me like a truck.\" Their first real fight, in the parking lot of a bar in Lordsburg. They lost. It's Monday night, afternoon. it's a weeknight \u2014 work tomorrow for most people. Early spring \u2014 wind season is starting. Dust storms possible.",
|
||||||
|
"seeds": [
|
||||||
|
"been binging Landman, loves the oil field drama",
|
||||||
|
"coaches youth sports, takes it more seriously than the parents do",
|
||||||
|
"comfortable talking about sex when it comes up",
|
||||||
|
"Convinced the government knows about things in the desert they won't talk about."
|
||||||
|
],
|
||||||
|
"verbal_fluency": "medium",
|
||||||
|
"calling_from": "in the bathtub, phone balanced on the edge"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"used_reasons": [
|
||||||
|
"their car's trip odometer resets itself to 0.0 every time they park at the grocery store \u2014 only at the grocery store, nowhere else \u2014 and it's been doing it for five months since they had the oil changed",
|
||||||
|
"their car radio turned itself on in the driveway at 2 AM playing a station that went off the air in 2003 \u2014 they checked, the station doesn't exist anymore",
|
||||||
|
"their church raised enough to pay off a family's medical debt anonymously",
|
||||||
|
"is being sued by their former business partner for $200k and just got served at their daughter's soccer game",
|
||||||
|
"walked into the wrong house in their subdivision \u2014 same floor plan, door was unlocked \u2014 sat down on the couch before the actual homeowner came out of the bathroom",
|
||||||
|
"found out their coworker who drives a new BMW and wears designer clothes is completely broke \u2014 the coworker accidentally left a bank statement on the printer showing a negative balance",
|
||||||
|
"their tenant is three months behind on rent and has a newborn \u2014 the caller needs the rental income to pay their own mortgage but can't live with themselves for evicting a baby",
|
||||||
|
"thinks couples who share a single social media account are hiding something and everyone knows it",
|
||||||
|
"had a near-death experience during a flash flood in a wash and the way time slowed down changed something fundamental in how they see each day",
|
||||||
|
"their town's only restaurant changed the recipe for the green chile and there's a petition with 200 signatures demanding they change it back \u2014 the caller started the petition",
|
||||||
|
"slept with their best friend's spouse at that friend's funeral reception \u2014 they were both grief-drunk and now they see each other every week because they're both in the dead friend's will as co-executors",
|
||||||
|
"their town had a power outage and everyone went outside and hung out in the street for three hours \u2014 it was the best night they've had in years and they're weirdly hoping it happens again",
|
||||||
|
"has been having phone sex with a stranger they met on a late-night chat line for six months \u2014 they know the person's voice better than their spouse's and they've started comparing the two out loud by accident",
|
||||||
|
"thinks the obsession with sourdough bread is ridiculous and a loaf from the store tastes the same",
|
||||||
|
"best friend from high school died in a car wreck last month and they hadn't talked in three years because of a stupid argument",
|
||||||
|
"accidentally waved back at someone who was waving at the person behind them \u2014 committed to it and had a five-minute conversation pretending they knew each other, exchanged numbers, and is now too deep to explain",
|
||||||
|
"thinks bumper stickers are a cry for attention and nobody's ever changed their mind because of one",
|
||||||
|
"completed their first full night of sleep without nightmares since coming home from deployment"
|
||||||
|
],
|
||||||
|
"ai_respond_mode": "manual",
|
||||||
|
"auto_followup": false,
|
||||||
|
"news_headlines": [],
|
||||||
|
"research_notes": {},
|
||||||
|
"caller_bases": {
|
||||||
|
"1": {
|
||||||
|
"name": "Greg",
|
||||||
|
"voice": "Timothy",
|
||||||
|
"returning": false,
|
||||||
|
"regular_id": null
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"name": "Candy",
|
||||||
|
"voice": "Kelsey",
|
||||||
|
"returning": false,
|
||||||
|
"regular_id": null
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"name": "Vernon",
|
||||||
|
"voice": "Vinny",
|
||||||
|
"returning": false,
|
||||||
|
"regular_id": null
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"name": "Angie",
|
||||||
|
"voice": "Julia",
|
||||||
|
"returning": true,
|
||||||
|
"regular_id": "bbb20b67"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"name": "Wendell",
|
||||||
|
"voice": "Hank",
|
||||||
|
"returning": false,
|
||||||
|
"regular_id": null
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"name": "Yolanda",
|
||||||
|
"voice": "Lauren",
|
||||||
|
"returning": false,
|
||||||
|
"regular_id": null
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"name": "Big Mike",
|
||||||
|
"voice": "Edward",
|
||||||
|
"returning": false,
|
||||||
|
"regular_id": null
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"name": "Luann",
|
||||||
|
"voice": "Serena",
|
||||||
|
"returning": false,
|
||||||
|
"regular_id": null
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"name": "Benny",
|
||||||
|
"voice": "Clive",
|
||||||
|
"returning": false,
|
||||||
|
"regular_id": null
|
||||||
|
},
|
||||||
|
"0": {
|
||||||
|
"name": "Sandy",
|
||||||
|
"voice": "Loretta",
|
||||||
|
"returning": false,
|
||||||
|
"regular_id": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pool_weights": {
|
||||||
|
"PROBLEMS": 0.23240905322989075,
|
||||||
|
"STORIES": 0.1759722154274807,
|
||||||
|
"GOSSIP": 0.14602822326391124,
|
||||||
|
"ADVICE": 0.12409358363552739,
|
||||||
|
"TOPIC_CALLIN": 0.09667013948808895,
|
||||||
|
"CELEBRATIONS": 0.07603761096793717,
|
||||||
|
"WEIRD": 0.14878917398716374
|
||||||
|
},
|
||||||
|
"caller_styles": {
|
||||||
|
"1": "COMMUNICATION STYLE: Bone dry. Says devastating things with zero inflection. Their humor sneaks up on you \u2014 you're not sure if they're joking until three seconds after they finish talking. Short, precise sentences. Never raises their voice. Energy level: low-medium. When pushed back on, they respond with one calm sentence that somehow makes the other person feel stupid. Conversational tendency: underreaction.",
|
||||||
|
"2": "COMMUNICATION STYLE: Called because they need to GET THIS OFF THEIR CHEST. Talks in capital letters. Uses 'honestly' and 'I'm not even kidding' a lot. The anger is specific and justified \u2014 this isn't random rage, this is 'let me tell you exactly what happened.' Energy level: very high. When pushed back on, they take a breath and say 'I hear you but...' and then get right back to the rant. Conversational tendency: building to a crescendo.",
|
||||||
|
"3": "COMMUNICATION STYLE: Treats the call like a set. Has bits prepared. Delivers serious information with a punchline chaser. Self-deprecating as a defense mechanism \u2014 makes fun of themselves before anyone else can. Energy level: high. When pushed back on, they deflect with humor. Getting a straight answer from them requires the host to push. Conversational tendency: turning everything into a bit.",
|
||||||
|
"4": "COMMUNICATION STYLE: Bone dry. Says devastating things with zero inflection. Their humor sneaks up on you \u2014 you're not sure if they're joking until three seconds after they finish talking. Short, precise sentences. Never raises their voice. Energy level: low-medium. When pushed back on, they respond with one calm sentence that somehow makes the other person feel stupid. Conversational tendency: underreaction.",
|
||||||
|
"5": "COMMUNICATION STYLE: Starts a sentence, gets distracted by their own tangent, starts another sentence, remembers the first one, tries to merge them. Asks 'where was I?' a lot. Not unintelligent \u2014 their brain just moves faster than their mouth. Lots of 'oh and another thing.' Energy level: medium-high but unfocused. When pushed back on, they agree enthusiastically and then immediately go off on another tangent. Conversational tendency: free association.",
|
||||||
|
"6": "COMMUNICATION STYLE: Clearly holding back. Gives vague answers to direct questions. Says 'I can't really get into that' about key details. The mystery IS the hook \u2014 makes you want to know what they're not saying. Energy level: low, controlled. When pushed back on, they deflect smoothly or change the subject. Getting the real story requires the host to work for it. Conversational tendency: strategic omission.",
|
||||||
|
"7": "COMMUNICATION STYLE: Comes in hot. Has an opinion about everything and isn't shy about sharing it. Interrupts. Disagrees first, thinks second. Not mean \u2014 just intense. Treats every conversation like a friendly argument. Energy level: high. When pushed back on, they lean IN, not away. They love a good debate and will take the opposite position just for sport. Conversational tendency: challenging everything.",
|
||||||
|
"8": "COMMUNICATION STYLE: Amped up. Talks fast, laughs loud, jumps between topics like they've had five espressos. Infectious enthusiasm \u2014 even bad news sounds exciting when they tell it. Uses exclamation energy without actually exclaiming. Energy level: very high. When pushed back on, they get even MORE animated and start talking with their hands (you can hear it). Conversational tendency: escalation.",
|
||||||
|
"9": "COMMUNICATION STYLE: Quiet, a little nervous. Short sentences, lots of pauses. Doesn't volunteer information \u2014 you have to pull it out of them. When they do open up it comes out in a rush. Gets flustered by direct questions. Tends to backtrack and qualify everything they say. Energy level: low. When pushed back on, they fold quickly and agree even if they don't mean it. Conversational tendency: understatement.",
|
||||||
|
"0": "COMMUNICATION STYLE: Quiet, a little nervous. Short sentences, lots of pauses. Doesn't volunteer information \u2014 you have to pull it out of them. When they do open up it comes out in a rush. Gets flustered by direct questions. Tends to backtrack and qualify everything they say. Energy level: low. When pushed back on, they fold quickly and agree even if they don't mean it. Conversational tendency: understatement."
|
||||||
|
},
|
||||||
|
"caller_shapes": {
|
||||||
|
"1": "standard",
|
||||||
|
"2": "confrontation",
|
||||||
|
"3": "standard",
|
||||||
|
"5": "am_i_the_asshole",
|
||||||
|
"6": "confrontation",
|
||||||
|
"7": "escalating_reveal",
|
||||||
|
"8": "quick_hit",
|
||||||
|
"9": "escalating_reveal",
|
||||||
|
"0": "am_i_the_asshole"
|
||||||
|
},
|
||||||
|
"tone_streak": [
|
||||||
|
"light",
|
||||||
|
"light",
|
||||||
|
"light",
|
||||||
|
"light",
|
||||||
|
"light",
|
||||||
|
"light",
|
||||||
|
"heavy",
|
||||||
|
"light",
|
||||||
|
"light",
|
||||||
|
"light",
|
||||||
|
"light",
|
||||||
|
"heavy",
|
||||||
|
"heavy",
|
||||||
|
"light",
|
||||||
|
"light",
|
||||||
|
"light",
|
||||||
|
"heavy",
|
||||||
|
"heavy"
|
||||||
|
],
|
||||||
|
"call_quality_signals": [],
|
||||||
|
"caller_queue": [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"8",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"7",
|
||||||
|
"9",
|
||||||
|
"0",
|
||||||
|
"6"
|
||||||
|
],
|
||||||
|
"relationship_context": {},
|
||||||
|
"intern_monitoring": true,
|
||||||
|
"costs": {
|
||||||
|
"total_cost_usd": 0.0,
|
||||||
|
"llm_cost_usd": 0.0,
|
||||||
|
"tts_cost_usd": 0.0,
|
||||||
|
"total_llm_calls": 0,
|
||||||
|
"total_tokens": 0,
|
||||||
|
"prompt_tokens": 0,
|
||||||
|
"completion_tokens": 0,
|
||||||
|
"by_category": {}
|
||||||
|
},
|
||||||
|
"saved_at": 1773697751.162024
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"voicemails": [],
|
||||||
|
"deleted_timestamps": [
|
||||||
|
1772294240,
|
||||||
|
1771212705,
|
||||||
|
1771146434,
|
||||||
|
1771146564,
|
||||||
|
1773545733,
|
||||||
|
1771146952,
|
||||||
|
1773531209,
|
||||||
|
1771244817,
|
||||||
|
1771244823,
|
||||||
|
1771213151
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -23,8 +23,7 @@ TMPFILE=$(mktemp)
|
|||||||
cat > "$TMPFILE" << 'DOCKERFILE'
|
cat > "$TMPFILE" << 'DOCKERFILE'
|
||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/* \
|
RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/* \
|
||||||
&& curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-27.5.1.tgz | tar xz --strip-components=1 -C /usr/local/bin docker/docker \
|
&& curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-27.5.1.tgz | tar xz --strip-components=1 -C /usr/local/bin docker/docker
|
||||||
&& apt-get purge -y curl && apt-get autoremove -y
|
|
||||||
RUN pip install --no-cache-dir requests yt-dlp
|
RUN pip install --no-cache-dir requests yt-dlp
|
||||||
COPY podcast_stats.py /app/podcast_stats.py
|
COPY podcast_stats.py /app/podcast_stats.py
|
||||||
COPY run_loop.sh /app/run_loop.sh
|
COPY run_loop.sh /app/run_loop.sh
|
||||||
@@ -42,7 +41,12 @@ cat > "$TMPFILE" << 'LOOPSCRIPT'
|
|||||||
echo "podcast-stats: starting hourly loop"
|
echo "podcast-stats: starting hourly loop"
|
||||||
while true; do
|
while true; do
|
||||||
echo "$(date -u '+%Y-%m-%dT%H:%M:%SZ') Running stats update..."
|
echo "$(date -u '+%Y-%m-%dT%H:%M:%SZ') Running stats update..."
|
||||||
python podcast_stats.py --json --upload 2>&1 || echo " ...failed, will retry next hour"
|
if python podcast_stats.py --json --upload 2>&1; then
|
||||||
|
[ -n "$HEARTBEAT_URL" ] && curl -s "${HEARTBEAT_URL}?status=up&msg=OK" > /dev/null
|
||||||
|
echo " ...done, heartbeat sent"
|
||||||
|
else
|
||||||
|
echo " ...failed, will retry next hour"
|
||||||
|
fi
|
||||||
echo "Sleeping 1 hour..."
|
echo "Sleeping 1 hour..."
|
||||||
sleep 3600
|
sleep 3600
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -0,0 +1,505 @@
|
|||||||
|
# Clip Social Media Upload Implementation Plan
|
||||||
|
|
||||||
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||||
|
|
||||||
|
**Goal:** Generate social media descriptions/hashtags for podcast clips and upload them to Instagram Reels + YouTube Shorts via Postiz API.
|
||||||
|
|
||||||
|
**Architecture:** Two changes — (1) extend `make_clips.py` to add a second LLM call that generates descriptions + hashtags, saved as `clips-metadata.json`, (2) new `upload_clips.py` script that reads that metadata and pushes clips through the self-hosted Postiz instance at `social.lukeattheroost.com`.
|
||||||
|
|
||||||
|
**Tech Stack:** Python, OpenRouter API (Claude Sonnet), Postiz REST API, requests library (already installed)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Add `generate_social_metadata()` to `make_clips.py`
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `make_clips.py:231-312` (after `select_clips_with_llm`)
|
||||||
|
|
||||||
|
**Step 1: Add the function after `select_clips_with_llm`**
|
||||||
|
|
||||||
|
Add this function at line ~314 (after `select_clips_with_llm` returns):
|
||||||
|
|
||||||
|
```python
|
||||||
|
def generate_social_metadata(clips: list[dict], labeled_transcript: str,
|
||||||
|
episode_number: int | None) -> list[dict]:
|
||||||
|
"""Generate social media descriptions and hashtags for each clip."""
|
||||||
|
if not OPENROUTER_API_KEY:
|
||||||
|
print("Error: OPENROUTER_API_KEY not set in .env")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
clips_summary = "\n".join(
|
||||||
|
f'{i+1}. "{c["title"]}" — {c["caption_text"]}'
|
||||||
|
for i, c in enumerate(clips)
|
||||||
|
)
|
||||||
|
|
||||||
|
episode_context = f"This is Episode {episode_number} of " if episode_number else "This is an episode of "
|
||||||
|
|
||||||
|
prompt = f"""{episode_context}the "Luke at the Roost" podcast — a late-night call-in show where AI-generated callers share stories, confessions, and hot takes with host Luke.
|
||||||
|
|
||||||
|
Here are {len(clips)} clips selected from this episode:
|
||||||
|
|
||||||
|
{clips_summary}
|
||||||
|
|
||||||
|
For each clip, generate:
|
||||||
|
1. description: A short, engaging description for social media (1-2 sentences, hook the viewer, conversational tone). Do NOT include hashtags in the description.
|
||||||
|
2. hashtags: An array of 5-8 hashtags. Always include #lukeattheroost and #podcast. Add topic-relevant and trending-style tags.
|
||||||
|
|
||||||
|
Respond with ONLY a JSON array matching the clip order:
|
||||||
|
[{{"description": "...", "hashtags": ["#tag1", "#tag2", ...]}}]"""
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
"https://openrouter.ai/api/v1/chat/completions",
|
||||||
|
headers={
|
||||||
|
"Authorization": f"Bearer {OPENROUTER_API_KEY}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
json={
|
||||||
|
"model": "anthropic/claude-sonnet-4-5",
|
||||||
|
"messages": [{"role": "user", "content": prompt}],
|
||||||
|
"max_tokens": 2048,
|
||||||
|
"temperature": 0.7,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.status_code != 200:
|
||||||
|
print(f"Error from OpenRouter: {response.text}")
|
||||||
|
return clips
|
||||||
|
|
||||||
|
content = response.json()["choices"][0]["message"]["content"].strip()
|
||||||
|
if content.startswith("```"):
|
||||||
|
content = re.sub(r"^```(?:json)?\n?", "", content)
|
||||||
|
content = re.sub(r"\n?```$", "", content)
|
||||||
|
|
||||||
|
try:
|
||||||
|
metadata = json.loads(content)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f"Error parsing social metadata: {e}")
|
||||||
|
return clips
|
||||||
|
|
||||||
|
for i, clip in enumerate(clips):
|
||||||
|
if i < len(metadata):
|
||||||
|
clip["description"] = metadata[i].get("description", "")
|
||||||
|
clip["hashtags"] = metadata[i].get("hashtags", [])
|
||||||
|
|
||||||
|
return clips
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Run existing tests to verify no breakage**
|
||||||
|
|
||||||
|
Run: `pytest tests/ -v`
|
||||||
|
Expected: All existing tests pass (this is a new function, no side effects yet)
|
||||||
|
|
||||||
|
**Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add make_clips.py
|
||||||
|
git commit -m "Add generate_social_metadata() for clip descriptions and hashtags"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Integrate metadata generation + JSON save into `main()`
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `make_clips.py:1082-1289` (inside `main()`)
|
||||||
|
|
||||||
|
**Step 1: Add metadata generation call and JSON save**
|
||||||
|
|
||||||
|
After the LLM clip selection step (~line 1196, after the clip summary print loop), add:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Step N: Generate social media metadata
|
||||||
|
print(f"\n[{extract_step - 1}/{step_total}] Generating social media descriptions...")
|
||||||
|
clips = generate_social_metadata(clips, labeled_transcript, episode_number)
|
||||||
|
for i, clip in enumerate(clips):
|
||||||
|
if "description" in clip:
|
||||||
|
print(f" Clip {i+1}: {clip['description'][:80]}...")
|
||||||
|
print(f" {' '.join(clip.get('hashtags', []))}")
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: This needs to be inserted BEFORE the audio extraction step, and the step numbering needs to be adjusted (total steps goes from 5/6 to 6/7).
|
||||||
|
|
||||||
|
At the end of `main()`, before the summary print, save the metadata JSON:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Save clips metadata for social upload
|
||||||
|
metadata_path = output_dir / "clips-metadata.json"
|
||||||
|
metadata = []
|
||||||
|
for i, clip in enumerate(clips):
|
||||||
|
slug = slugify(clip["title"])
|
||||||
|
metadata.append({
|
||||||
|
"title": clip["title"],
|
||||||
|
"clip_file": f"clip-{i+1}-{slug}.mp4",
|
||||||
|
"audio_file": f"clip-{i+1}-{slug}.mp3",
|
||||||
|
"caption_text": clip.get("caption_text", ""),
|
||||||
|
"description": clip.get("description", ""),
|
||||||
|
"hashtags": clip.get("hashtags", []),
|
||||||
|
"start_time": clip["start_time"],
|
||||||
|
"end_time": clip["end_time"],
|
||||||
|
"duration": round(clip["end_time"] - clip["start_time"], 1),
|
||||||
|
"episode_number": episode_number,
|
||||||
|
})
|
||||||
|
with open(metadata_path, "w") as f:
|
||||||
|
json.dump(metadata, f, indent=2)
|
||||||
|
print(f"\nSocial metadata: {metadata_path}")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Adjust step numbering**
|
||||||
|
|
||||||
|
The pipeline steps need to account for the new metadata step. Update `step_total` calculation:
|
||||||
|
|
||||||
|
```python
|
||||||
|
step_total = (7 if two_pass else 6)
|
||||||
|
```
|
||||||
|
|
||||||
|
And shift the extract/video step numbers up by 1.
|
||||||
|
|
||||||
|
**Step 3: Test manually**
|
||||||
|
|
||||||
|
Run: `python make_clips.py --help`
|
||||||
|
Expected: No import errors, help displays normally
|
||||||
|
|
||||||
|
**Step 4: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add make_clips.py
|
||||||
|
git commit -m "Save clips-metadata.json with social descriptions and hashtags"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: Create `upload_clips.py` — core structure and Postiz API helpers
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `upload_clips.py`
|
||||||
|
|
||||||
|
**Step 1: Write the script**
|
||||||
|
|
||||||
|
```python
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Upload podcast clips to Instagram Reels and YouTube Shorts via Postiz.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python upload_clips.py clips/episode-12/
|
||||||
|
python upload_clips.py clips/episode-12/ --clip 1
|
||||||
|
python upload_clips.py clips/episode-12/ --youtube-only
|
||||||
|
python upload_clips.py clips/episode-12/ --instagram-only
|
||||||
|
python upload_clips.py clips/episode-12/ --schedule "2026-02-16T10:00:00"
|
||||||
|
python upload_clips.py clips/episode-12/ --yes # skip confirmation
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
|
||||||
|
load_dotenv(Path(__file__).parent / ".env")
|
||||||
|
|
||||||
|
POSTIZ_API_KEY = os.getenv("POSTIZ_API_KEY")
|
||||||
|
POSTIZ_URL = os.getenv("POSTIZ_URL", "https://social.lukeattheroost.com")
|
||||||
|
|
||||||
|
|
||||||
|
def get_api_url(path: str) -> str:
|
||||||
|
"""Build full Postiz API URL."""
|
||||||
|
base = POSTIZ_URL.rstrip("/")
|
||||||
|
# Postiz self-hosted API is at /api/public/v1 when NEXT_PUBLIC_BACKEND_URL is the app URL
|
||||||
|
# but the docs say /public/v1 relative to backend URL. Try the standard path.
|
||||||
|
return f"{base}/api/public/v1{path}"
|
||||||
|
|
||||||
|
|
||||||
|
def api_headers() -> dict:
|
||||||
|
return {
|
||||||
|
"Authorization": POSTIZ_API_KEY,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_integrations() -> list[dict]:
|
||||||
|
"""Fetch connected social accounts from Postiz."""
|
||||||
|
resp = requests.get(get_api_url("/integrations"), headers=api_headers(), timeout=15)
|
||||||
|
if resp.status_code != 200:
|
||||||
|
print(f"Error fetching integrations: {resp.status_code} {resp.text[:200]}")
|
||||||
|
sys.exit(1)
|
||||||
|
return resp.json()
|
||||||
|
|
||||||
|
|
||||||
|
def find_integration(integrations: list[dict], provider: str) -> dict | None:
|
||||||
|
"""Find integration by provider name (e.g. 'instagram', 'youtube')."""
|
||||||
|
for integ in integrations:
|
||||||
|
if integ.get("providerIdentifier", "").startswith(provider):
|
||||||
|
return integ
|
||||||
|
if integ.get("provider", "").startswith(provider):
|
||||||
|
return integ
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def upload_file(file_path: Path) -> dict:
|
||||||
|
"""Upload a file to Postiz. Returns {id, path}."""
|
||||||
|
headers = {"Authorization": POSTIZ_API_KEY}
|
||||||
|
with open(file_path, "rb") as f:
|
||||||
|
resp = requests.post(
|
||||||
|
get_api_url("/upload"),
|
||||||
|
headers=headers,
|
||||||
|
files={"file": (file_path.name, f, "video/mp4")},
|
||||||
|
timeout=120,
|
||||||
|
)
|
||||||
|
if resp.status_code != 200:
|
||||||
|
print(f"Upload failed: {resp.status_code} {resp.text[:200]}")
|
||||||
|
return {}
|
||||||
|
return resp.json()
|
||||||
|
|
||||||
|
|
||||||
|
def create_post(integration_id: str, content: str, media: dict,
|
||||||
|
settings: dict, schedule: str | None = None) -> dict:
|
||||||
|
"""Create a post on Postiz."""
|
||||||
|
post_type = "schedule" if schedule else "now"
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"type": post_type,
|
||||||
|
"posts": [
|
||||||
|
{
|
||||||
|
"integration": {"id": integration_id},
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"content": content,
|
||||||
|
"image": [media] if media else [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": settings,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
if schedule:
|
||||||
|
payload["date"] = schedule
|
||||||
|
|
||||||
|
resp = requests.post(
|
||||||
|
get_api_url("/posts"),
|
||||||
|
headers=api_headers(),
|
||||||
|
json=payload,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
if resp.status_code not in (200, 201):
|
||||||
|
print(f"Post creation failed: {resp.status_code} {resp.text[:300]}")
|
||||||
|
return {}
|
||||||
|
return resp.json()
|
||||||
|
|
||||||
|
|
||||||
|
def build_instagram_content(clip: dict) -> str:
|
||||||
|
"""Build Instagram post content: description + hashtags."""
|
||||||
|
parts = [clip.get("description", clip.get("caption_text", ""))]
|
||||||
|
hashtags = clip.get("hashtags", [])
|
||||||
|
if hashtags:
|
||||||
|
parts.append("\n\n" + " ".join(hashtags))
|
||||||
|
return "".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
def build_youtube_content(clip: dict) -> str:
|
||||||
|
"""Build YouTube description."""
|
||||||
|
parts = [clip.get("description", clip.get("caption_text", ""))]
|
||||||
|
hashtags = clip.get("hashtags", [])
|
||||||
|
if hashtags:
|
||||||
|
parts.append("\n\n" + " ".join(hashtags))
|
||||||
|
parts.append("\n\nListen to the full episode: lukeattheroost.com")
|
||||||
|
return "".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Upload podcast clips to social media via Postiz")
|
||||||
|
parser.add_argument("clips_dir", help="Path to clips directory (e.g. clips/episode-12/)")
|
||||||
|
parser.add_argument("--clip", "-c", type=int, help="Upload only clip N (1-indexed)")
|
||||||
|
parser.add_argument("--instagram-only", action="store_true", help="Upload to Instagram only")
|
||||||
|
parser.add_argument("--youtube-only", action="store_true", help="Upload to YouTube only")
|
||||||
|
parser.add_argument("--schedule", "-s", help="Schedule time (ISO 8601, e.g. 2026-02-16T10:00:00)")
|
||||||
|
parser.add_argument("--yes", "-y", action="store_true", help="Skip confirmation prompt")
|
||||||
|
parser.add_argument("--dry-run", action="store_true", help="Show what would be uploaded without posting")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not POSTIZ_API_KEY:
|
||||||
|
print("Error: POSTIZ_API_KEY not set in .env")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
clips_dir = Path(args.clips_dir).expanduser().resolve()
|
||||||
|
metadata_path = clips_dir / "clips-metadata.json"
|
||||||
|
|
||||||
|
if not metadata_path.exists():
|
||||||
|
print(f"Error: No clips-metadata.json found in {clips_dir}")
|
||||||
|
print("Run make_clips.py first to generate clips and metadata.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(metadata_path) as f:
|
||||||
|
clips = json.load(f)
|
||||||
|
|
||||||
|
if args.clip:
|
||||||
|
if args.clip < 1 or args.clip > len(clips):
|
||||||
|
print(f"Error: Clip {args.clip} not found (have {len(clips)} clips)")
|
||||||
|
sys.exit(1)
|
||||||
|
clips = [clips[args.clip - 1]]
|
||||||
|
|
||||||
|
# Determine which platforms to post to
|
||||||
|
do_instagram = not args.youtube_only
|
||||||
|
do_youtube = not args.instagram_only
|
||||||
|
|
||||||
|
# Fetch integrations from Postiz
|
||||||
|
print("Fetching connected accounts from Postiz...")
|
||||||
|
integrations = fetch_integrations()
|
||||||
|
|
||||||
|
ig_integration = None
|
||||||
|
yt_integration = None
|
||||||
|
|
||||||
|
if do_instagram:
|
||||||
|
ig_integration = find_integration(integrations, "instagram")
|
||||||
|
if not ig_integration:
|
||||||
|
print("Warning: No Instagram account connected in Postiz")
|
||||||
|
do_instagram = False
|
||||||
|
|
||||||
|
if do_youtube:
|
||||||
|
yt_integration = find_integration(integrations, "youtube")
|
||||||
|
if not yt_integration:
|
||||||
|
print("Warning: No YouTube account connected in Postiz")
|
||||||
|
do_youtube = False
|
||||||
|
|
||||||
|
if not do_instagram and not do_youtube:
|
||||||
|
print("Error: No platforms available to upload to")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Show summary
|
||||||
|
platforms = []
|
||||||
|
if do_instagram:
|
||||||
|
platforms.append(f"Instagram Reels ({ig_integration.get('name', 'connected')})")
|
||||||
|
if do_youtube:
|
||||||
|
platforms.append(f"YouTube Shorts ({yt_integration.get('name', 'connected')})")
|
||||||
|
|
||||||
|
print(f"\nUploading {len(clips)} clip(s) to: {', '.join(platforms)}")
|
||||||
|
if args.schedule:
|
||||||
|
print(f"Scheduled for: {args.schedule}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
for i, clip in enumerate(clips):
|
||||||
|
print(f" {i+1}. \"{clip['title']}\" ({clip['duration']:.0f}s)")
|
||||||
|
print(f" {clip.get('description', '')[:80]}")
|
||||||
|
print(f" {' '.join(clip.get('hashtags', []))}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
if args.dry_run:
|
||||||
|
print("Dry run — nothing uploaded.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not args.yes:
|
||||||
|
confirm = input("Proceed? [y/N] ").strip().lower()
|
||||||
|
if confirm != "y":
|
||||||
|
print("Cancelled.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Upload each clip
|
||||||
|
for i, clip in enumerate(clips):
|
||||||
|
clip_file = clips_dir / clip["clip_file"]
|
||||||
|
if not clip_file.exists():
|
||||||
|
print(f" Clip {i+1}: Video file not found: {clip_file}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"\n Clip {i+1}: \"{clip['title']}\"")
|
||||||
|
|
||||||
|
# Upload video to Postiz
|
||||||
|
print(f" Uploading {clip_file.name}...")
|
||||||
|
media = upload_file(clip_file)
|
||||||
|
if not media:
|
||||||
|
print(f" Failed to upload video, skipping")
|
||||||
|
continue
|
||||||
|
print(f" Uploaded: {media.get('path', 'ok')}")
|
||||||
|
|
||||||
|
# Post to Instagram Reels
|
||||||
|
if do_instagram:
|
||||||
|
print(f" Posting to Instagram Reels...")
|
||||||
|
content = build_instagram_content(clip)
|
||||||
|
settings = {
|
||||||
|
"__type": "instagram",
|
||||||
|
"post_type": "reel",
|
||||||
|
}
|
||||||
|
result = create_post(
|
||||||
|
ig_integration["id"], content, media, settings, args.schedule
|
||||||
|
)
|
||||||
|
if result:
|
||||||
|
print(f" Instagram: Posted!")
|
||||||
|
else:
|
||||||
|
print(f" Instagram: Failed")
|
||||||
|
|
||||||
|
# Post to YouTube Shorts
|
||||||
|
if do_youtube:
|
||||||
|
print(f" Posting to YouTube Shorts...")
|
||||||
|
content = build_youtube_content(clip)
|
||||||
|
settings = {
|
||||||
|
"__type": "youtube",
|
||||||
|
"title": clip["title"],
|
||||||
|
"type": "short",
|
||||||
|
"selfDeclaredMadeForKids": False,
|
||||||
|
"tags": [h.lstrip("#") for h in clip.get("hashtags", [])],
|
||||||
|
}
|
||||||
|
result = create_post(
|
||||||
|
yt_integration["id"], content, media, settings, args.schedule
|
||||||
|
)
|
||||||
|
if result:
|
||||||
|
print(f" YouTube: Posted!")
|
||||||
|
else:
|
||||||
|
print(f" YouTube: Failed")
|
||||||
|
|
||||||
|
print(f"\nDone!")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Add `POSTIZ_API_KEY` and `POSTIZ_URL` to `.env`**
|
||||||
|
|
||||||
|
Add to `.env`:
|
||||||
|
```
|
||||||
|
POSTIZ_API_KEY=your-postiz-api-key-here
|
||||||
|
POSTIZ_URL=https://social.lukeattheroost.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Get your API key from Postiz Settings page.
|
||||||
|
|
||||||
|
**Step 3: Test the script loads**
|
||||||
|
|
||||||
|
Run: `python upload_clips.py --help`
|
||||||
|
Expected: Help text displays with all flags
|
||||||
|
|
||||||
|
**Step 4: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add upload_clips.py
|
||||||
|
git commit -m "Add upload_clips.py for posting clips to Instagram/YouTube via Postiz"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: Test with real Postiz instance
|
||||||
|
|
||||||
|
**Step 1: Get Postiz API key**
|
||||||
|
|
||||||
|
Go to `https://social.lukeattheroost.com` → Settings → API Keys → Generate key. Add to `.env` as `POSTIZ_API_KEY`.
|
||||||
|
|
||||||
|
**Step 2: Verify integrations endpoint**
|
||||||
|
|
||||||
|
Run: `python -c "from upload_clips import *; print(json.dumps(fetch_integrations(), indent=2))"`
|
||||||
|
|
||||||
|
This confirms the API key works and shows connected Instagram/YouTube accounts. Note the integration IDs and provider identifiers — if `find_integration()` doesn't match correctly, adjust the provider string matching.
|
||||||
|
|
||||||
|
**Step 3: Dry-run with existing clips**
|
||||||
|
|
||||||
|
Run: `python upload_clips.py clips/episode-12/ --dry-run`
|
||||||
|
Expected: Shows clip summary, "Dry run — nothing uploaded."
|
||||||
|
|
||||||
|
**Step 4: Upload a single test clip**
|
||||||
|
|
||||||
|
Run: `python upload_clips.py clips/episode-12/ --clip 1 --instagram-only`
|
||||||
|
|
||||||
|
Check Postiz dashboard and Instagram to verify it posted as a Reel.
|
||||||
|
|
||||||
|
**Step 5: Commit .env update (do NOT commit the key itself)**
|
||||||
|
|
||||||
|
The `.env` is gitignored so no action needed. Just ensure the key names are documented in CLAUDE.md if desired.
|
||||||
@@ -0,0 +1,402 @@
|
|||||||
|
# Idents Playback Implementation Plan
|
||||||
|
|
||||||
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||||
|
|
||||||
|
**Goal:** Add an idents section that loads MP3s from `idents/` and plays them through the ads channel (ch 11), with a separate "idents" stem for post-production.
|
||||||
|
|
||||||
|
**Architecture:** Mirrors the existing ads system — dropdown + play/stop buttons, same audio channel, mutually exclusive with ads. Idents get their own stem in stem_recorder so they can be mixed independently in post-production.
|
||||||
|
|
||||||
|
**Tech Stack:** Python (FastAPI), sounddevice, librosa, vanilla JS
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Add idents_dir to config
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `backend/config.py:46-47`
|
||||||
|
|
||||||
|
**Step 1: Add idents_dir path**
|
||||||
|
|
||||||
|
After `ads_dir` (line 46), add:
|
||||||
|
|
||||||
|
```python
|
||||||
|
idents_dir: Path = base_dir / "idents"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Create the idents directory**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p idents
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add backend/config.py
|
||||||
|
git commit -m "Add idents_dir to config"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Add "idents" stem to stem_recorder
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `backend/services/stem_recorder.py:10`
|
||||||
|
|
||||||
|
**Step 1: Add "idents" to STEM_NAMES**
|
||||||
|
|
||||||
|
Change line 10 from:
|
||||||
|
|
||||||
|
```python
|
||||||
|
STEM_NAMES = ["host", "caller", "music", "sfx", "ads"]
|
||||||
|
```
|
||||||
|
|
||||||
|
to:
|
||||||
|
|
||||||
|
```python
|
||||||
|
STEM_NAMES = ["host", "caller", "music", "sfx", "ads", "idents"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Add "idents" to postprod.py STEM_NAMES**
|
||||||
|
|
||||||
|
In `postprod.py:20`, change:
|
||||||
|
|
||||||
|
```python
|
||||||
|
STEM_NAMES = ["host", "caller", "music", "sfx", "ads"]
|
||||||
|
```
|
||||||
|
|
||||||
|
to:
|
||||||
|
|
||||||
|
```python
|
||||||
|
STEM_NAMES = ["host", "caller", "music", "sfx", "ads", "idents"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Also update `postprod.py:72` — the `remove_gaps` content detection line — add idents:
|
||||||
|
|
||||||
|
```python
|
||||||
|
content = stems["host"] + stems["caller"] + stems["sfx"] + stems["ads"] + stems["idents"]
|
||||||
|
```
|
||||||
|
|
||||||
|
And in `mix_stems` (line 411), add idents level:
|
||||||
|
|
||||||
|
```python
|
||||||
|
levels = {"host": 0, "caller": 0, "music": -6, "sfx": -10, "ads": 0, "idents": 0}
|
||||||
|
```
|
||||||
|
|
||||||
|
And in stereo pans (line 420):
|
||||||
|
|
||||||
|
```python
|
||||||
|
pans = {"host": 0.0, "caller": 0.15, "music": 0.0, "sfx": 0.0, "ads": 0.0, "idents": 0.0}
|
||||||
|
```
|
||||||
|
|
||||||
|
And in `match_voice_levels` (line 389), add "idents":
|
||||||
|
|
||||||
|
```python
|
||||||
|
for name in ["host", "caller", "ads", "idents"]:
|
||||||
|
```
|
||||||
|
|
||||||
|
And in gap removal limiter section (line 777-778):
|
||||||
|
|
||||||
|
```python
|
||||||
|
for name in ["ads", "sfx", "idents"]:
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add backend/services/stem_recorder.py postprod.py
|
||||||
|
git commit -m "Add idents stem to recorder and postprod"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: Add play_ident / stop_ident to audio service
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `backend/services/audio.py`
|
||||||
|
|
||||||
|
**Step 1: Add ident state vars to __init__ (after line 40)**
|
||||||
|
|
||||||
|
After the ad playback state block (lines 35-40), add:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Ident playback state
|
||||||
|
self._ident_stream: Optional[sd.OutputStream] = None
|
||||||
|
self._ident_data: Optional[np.ndarray] = None
|
||||||
|
self._ident_resampled: Optional[np.ndarray] = None
|
||||||
|
self._ident_position: int = 0
|
||||||
|
self._ident_playing: bool = False
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Add play_ident method (after stop_ad, ~line 1006)**
|
||||||
|
|
||||||
|
Insert after `stop_ad` method. This is a copy of `play_ad` with:
|
||||||
|
- `_ad_*` → `_ident_*`
|
||||||
|
- Calls `self.stop_ad()` at the start (mutual exclusion)
|
||||||
|
- Stem recording writes to `"idents"` instead of `"ads"`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def play_ident(self, file_path: str):
|
||||||
|
"""Load and play an ident file once (no loop) on the ad channel"""
|
||||||
|
import librosa
|
||||||
|
|
||||||
|
path = Path(file_path)
|
||||||
|
if not path.exists():
|
||||||
|
print(f"Ident file not found: {file_path}")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.stop_ident()
|
||||||
|
self.stop_ad()
|
||||||
|
|
||||||
|
try:
|
||||||
|
audio, sr = librosa.load(str(path), sr=self.output_sample_rate, mono=True)
|
||||||
|
self._ident_data = audio.astype(np.float32)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to load ident: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
self._ident_playing = True
|
||||||
|
self._ident_position = 0
|
||||||
|
|
||||||
|
if self.output_device is None:
|
||||||
|
num_channels = 2
|
||||||
|
device = None
|
||||||
|
device_sr = self.output_sample_rate
|
||||||
|
channel_idx = 0
|
||||||
|
else:
|
||||||
|
device_info = sd.query_devices(self.output_device)
|
||||||
|
num_channels = device_info['max_output_channels']
|
||||||
|
device_sr = int(device_info['default_samplerate'])
|
||||||
|
device = self.output_device
|
||||||
|
channel_idx = min(self.ad_channel, num_channels) - 1
|
||||||
|
|
||||||
|
if self.output_sample_rate != device_sr:
|
||||||
|
self._ident_resampled = librosa.resample(
|
||||||
|
self._ident_data, orig_sr=self.output_sample_rate, target_sr=device_sr
|
||||||
|
).astype(np.float32)
|
||||||
|
else:
|
||||||
|
self._ident_resampled = self._ident_data
|
||||||
|
|
||||||
|
def callback(outdata, frames, time_info, status):
|
||||||
|
outdata[:] = 0
|
||||||
|
if not self._ident_playing or self._ident_resampled is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
remaining = len(self._ident_resampled) - self._ident_position
|
||||||
|
if remaining >= frames:
|
||||||
|
chunk = self._ident_resampled[self._ident_position:self._ident_position + frames]
|
||||||
|
outdata[:, channel_idx] = chunk
|
||||||
|
if self.stem_recorder:
|
||||||
|
self.stem_recorder.write_sporadic("idents", chunk.copy(), device_sr)
|
||||||
|
self._ident_position += frames
|
||||||
|
else:
|
||||||
|
if remaining > 0:
|
||||||
|
outdata[:remaining, channel_idx] = self._ident_resampled[self._ident_position:]
|
||||||
|
self._ident_playing = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._ident_stream = sd.OutputStream(
|
||||||
|
device=device,
|
||||||
|
channels=num_channels,
|
||||||
|
samplerate=device_sr,
|
||||||
|
dtype=np.float32,
|
||||||
|
callback=callback,
|
||||||
|
blocksize=2048
|
||||||
|
)
|
||||||
|
self._ident_stream.start()
|
||||||
|
print(f"Ident playback started on ch {self.ad_channel} @ {device_sr}Hz")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ident playback error: {e}")
|
||||||
|
self._ident_playing = False
|
||||||
|
|
||||||
|
def stop_ident(self):
|
||||||
|
"""Stop ident playback"""
|
||||||
|
self._ident_playing = False
|
||||||
|
if self._ident_stream:
|
||||||
|
self._ident_stream.stop()
|
||||||
|
self._ident_stream.close()
|
||||||
|
self._ident_stream = None
|
||||||
|
self._ident_position = 0
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3: Add `self.stop_ident()` to top of play_ad (line 935)**
|
||||||
|
|
||||||
|
In `play_ad`, after `self.stop_ad()` (line 935), add:
|
||||||
|
|
||||||
|
```python
|
||||||
|
self.stop_ident()
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 4: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add backend/services/audio.py
|
||||||
|
git commit -m "Add play_ident/stop_ident to audio service"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: Add idents API endpoints
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `backend/main.py` (after ads endpoints, ~line 4362)
|
||||||
|
|
||||||
|
**Step 1: Add IDENT_DISPLAY_NAMES and endpoints**
|
||||||
|
|
||||||
|
Insert after the ads stop endpoint (line 4362):
|
||||||
|
|
||||||
|
```python
|
||||||
|
|
||||||
|
# --- Idents Endpoints ---
|
||||||
|
|
||||||
|
IDENT_DISPLAY_NAMES = {}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/api/idents")
|
||||||
|
async def get_idents():
|
||||||
|
"""Get available ident tracks, shuffled"""
|
||||||
|
ident_list = []
|
||||||
|
if settings.idents_dir.exists():
|
||||||
|
for ext in ['*.wav', '*.mp3', '*.flac']:
|
||||||
|
for f in settings.idents_dir.glob(ext):
|
||||||
|
ident_list.append({
|
||||||
|
"name": IDENT_DISPLAY_NAMES.get(f.stem, f.stem),
|
||||||
|
"file": f.name,
|
||||||
|
"path": str(f)
|
||||||
|
})
|
||||||
|
random.shuffle(ident_list)
|
||||||
|
return {"idents": ident_list}
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/api/idents/play")
|
||||||
|
async def play_ident(request: MusicRequest):
|
||||||
|
"""Play an ident once on the ad channel (ch 11)"""
|
||||||
|
ident_path = settings.idents_dir / request.track
|
||||||
|
if not ident_path.exists():
|
||||||
|
raise HTTPException(404, "Ident not found")
|
||||||
|
|
||||||
|
if audio_service._music_playing:
|
||||||
|
audio_service.stop_music(fade_duration=1.0)
|
||||||
|
await asyncio.sleep(1.1)
|
||||||
|
audio_service.play_ident(str(ident_path))
|
||||||
|
return {"status": "playing", "track": request.track}
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/api/idents/stop")
|
||||||
|
async def stop_ident():
|
||||||
|
"""Stop ident playback"""
|
||||||
|
audio_service.stop_ident()
|
||||||
|
return {"status": "stopped"}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add backend/main.py
|
||||||
|
git commit -m "Add idents API endpoints"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 5: Add idents UI section and JS functions
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `frontend/index.html:113` (after ads section)
|
||||||
|
- Modify: `frontend/js/app.js`
|
||||||
|
|
||||||
|
**Step 1: Add Idents HTML section**
|
||||||
|
|
||||||
|
After the Ads section closing `</section>` (line 113), add:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Idents -->
|
||||||
|
<section class="music-section">
|
||||||
|
<h2>Idents</h2>
|
||||||
|
<select id="ident-select"></select>
|
||||||
|
<div class="music-controls">
|
||||||
|
<button id="ident-play-btn">Play Ident</button>
|
||||||
|
<button id="ident-stop-btn">Stop</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Add loadIdents, playIdent, stopIdent to app.js**
|
||||||
|
|
||||||
|
After `stopAd()` function (~line 773), add:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async function loadIdents() {
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/idents');
|
||||||
|
const data = await res.json();
|
||||||
|
const idents = data.idents || [];
|
||||||
|
|
||||||
|
const select = document.getElementById('ident-select');
|
||||||
|
if (!select) return;
|
||||||
|
|
||||||
|
const previousValue = select.value;
|
||||||
|
select.innerHTML = '';
|
||||||
|
|
||||||
|
idents.forEach(ident => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = ident.file;
|
||||||
|
option.textContent = ident.name;
|
||||||
|
select.appendChild(option);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (previousValue && [...select.options].some(o => o.value === previousValue)) {
|
||||||
|
select.value = previousValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Loaded', idents.length, 'idents');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('loadIdents error:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function playIdent() {
|
||||||
|
await loadIdents();
|
||||||
|
const select = document.getElementById('ident-select');
|
||||||
|
const track = select?.value;
|
||||||
|
if (!track) return;
|
||||||
|
|
||||||
|
await fetch('/api/idents/play', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ track, action: 'play' })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function stopIdent() {
|
||||||
|
await fetch('/api/idents/stop', { method: 'POST' });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3: Add event listeners in initEventListeners**
|
||||||
|
|
||||||
|
After the ads event listeners (line 190), add:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Idents
|
||||||
|
document.getElementById('ident-play-btn')?.addEventListener('click', playIdent);
|
||||||
|
document.getElementById('ident-stop-btn')?.addEventListener('click', stopIdent);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 4: Add loadIdents() to DOMContentLoaded init**
|
||||||
|
|
||||||
|
After `await loadAds();` (line 59), add:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
await loadIdents();
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 5: Bump cache buster on app.js script tag**
|
||||||
|
|
||||||
|
In `index.html:243`, change `?v=17` to `?v=18`.
|
||||||
|
|
||||||
|
**Step 6: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add frontend/index.html frontend/js/app.js
|
||||||
|
git commit -m "Add idents UI section and JS functions"
|
||||||
|
```
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Clips Page & Landing Page Redesign
|
||||||
|
|
||||||
|
## Clips Page (`/clips`)
|
||||||
|
|
||||||
|
Responsive grid gallery of podcast clips with click-to-play YouTube embeds.
|
||||||
|
|
||||||
|
**Grid:** 3 columns desktop, 2 tablet, 1 mobile. Cards use 9:16 vertical aspect ratio.
|
||||||
|
|
||||||
|
**Card pre-click:** Dark bg-light card with clip title (bold), episode label, centered orange play button, description text below. Matches site aesthetic.
|
||||||
|
|
||||||
|
**Card playing:** Click swaps card for YouTube Shorts iframe (`youtube-nocookie.com`, autoplay). Fills same 9:16 space.
|
||||||
|
|
||||||
|
**Data:** Static `website/data/clips.json` aggregated from per-episode `clips-metadata.json` files. Each entry: title, description, episode_number, optional `youtube_id`. Cards without youtube_id show no play button.
|
||||||
|
|
||||||
|
**Featured row:** Top 3 hand-picked clips displayed larger, followed by full grid below.
|
||||||
|
|
||||||
|
**Nav:** "Clips" added to hero secondary links and footer nav.
|
||||||
|
|
||||||
|
## Landing Page Improvements
|
||||||
|
|
||||||
|
**About section** (between hero and episodes): Centered text block. Show description + AI teaser line ("Part human callers, part AI-generated characters, fully unhinged advice") + "See how it works" link. No card background.
|
||||||
|
|
||||||
|
**Clips highlight** (between about and episodes): Horizontal row of 3 featured clips, same card style as clips page. "Best Clips" header with "See all clips" link.
|
||||||
|
|
||||||
|
**Final section order:** Banner → Hero → About → Featured Clips → Episodes → Testimonials → Footer
|
||||||
|
|
||||||
|
## How It Works — Reaper Video
|
||||||
|
|
||||||
|
New "Post-Production Automation" section with native `<video>` tag (mp4 on CDN). Shows Reaper automating silence removal, ad ducking, loudness normalization. Wrapped in hiw-hero-card style container.
|
||||||
@@ -17,6 +17,26 @@
|
|||||||
<button id="export-session-btn">Export</button>
|
<button id="export-session-btn">Export</button>
|
||||||
<button id="settings-btn">Settings</button>
|
<button id="settings-btn">Settings</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="theme-bar">
|
||||||
|
<label for="show-theme-input" class="theme-label">Theme:</label>
|
||||||
|
<input type="text" id="show-theme-input" class="theme-input" placeholder="e.g. St. Patrick's Day" maxlength="100">
|
||||||
|
<button id="set-theme-btn" class="theme-btn set" title="Set show theme">Set</button>
|
||||||
|
<button id="clear-theme-btn" class="theme-btn clear hidden" title="Clear theme">✕</button>
|
||||||
|
</div>
|
||||||
|
<div id="show-clock" class="show-clock">
|
||||||
|
<span class="clock-time" id="clock-time"></span>
|
||||||
|
<span id="show-timers" class="show-timers hidden">
|
||||||
|
<span class="clock-divider">|</span>
|
||||||
|
<span class="clock-label">On Air:</span>
|
||||||
|
<span class="clock-value" id="clock-runtime">0:00:00</span>
|
||||||
|
<span class="clock-divider">|</span>
|
||||||
|
<span class="clock-label">Est. Final:</span>
|
||||||
|
<span class="clock-value clock-estimate" id="clock-estimate">0:00</span>
|
||||||
|
<span class="clock-divider">|</span>
|
||||||
|
<span class="clock-label">Cost:</span>
|
||||||
|
<span class="clock-value clock-cost" id="clock-cost">$0.00</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
@@ -50,24 +70,67 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div id="call-status" class="call-status">No active call</div>
|
<div id="call-status" class="call-status">No active call</div>
|
||||||
<details id="caller-background-details" class="caller-background hidden">
|
<div id="caller-info-panel" class="caller-info-panel hidden">
|
||||||
<summary>Caller Background</summary>
|
<div class="caller-info-row">
|
||||||
|
<span id="caller-shape-badge" class="info-badge shape"></span>
|
||||||
|
<span id="caller-energy-badge" class="info-badge energy"></span>
|
||||||
|
<span id="caller-emotion" class="info-badge emotion"></span>
|
||||||
|
</div>
|
||||||
|
<div id="caller-signature" class="caller-signature"></div>
|
||||||
|
<div id="caller-situation" class="caller-situation"></div>
|
||||||
|
<details id="caller-background-details" class="caller-background-full">
|
||||||
|
<summary>Full Background</summary>
|
||||||
<div id="caller-background"></div>
|
<div id="caller-background"></div>
|
||||||
</details>
|
</details>
|
||||||
<button id="hangup-btn" class="hangup-btn" disabled>Hang Up</button>
|
</div>
|
||||||
|
<div class="call-actions">
|
||||||
|
<button id="wrapup-btn" class="wrapup-btn" disabled>Wrap It Up <span class="shortcut-label">W</span></button>
|
||||||
|
<button id="hangup-btn" class="hangup-btn" disabled>Hang Up <span class="shortcut-label">H</span></button>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Call Queue -->
|
<!-- Call Queue -->
|
||||||
<section class="queue-section">
|
<section class="queue-section">
|
||||||
<h2>Incoming Calls <span style="font-size:0.6em;font-weight:normal;color:var(--text-muted);">(208) 439-5853</span></h2>
|
<h2>Incoming Calls <span class="section-subtitle">(208) 439-5853</span></h2>
|
||||||
<div id="call-queue" class="call-queue">
|
<div id="call-queue" class="call-queue">
|
||||||
<div class="queue-empty">No callers waiting</div>
|
<div class="queue-empty">No callers waiting</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Voicemail -->
|
||||||
|
<section class="voicemail-section">
|
||||||
|
<h2>Voicemail <span id="voicemail-badge" class="voicemail-badge hidden">0</span></h2>
|
||||||
|
<div id="voicemail-list" class="voicemail-list">
|
||||||
|
<div class="queue-empty">No voicemails</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Listener Emails -->
|
||||||
|
<section class="voicemail-section">
|
||||||
|
<h2>Emails <span id="email-badge" class="voicemail-badge hidden">0</span></h2>
|
||||||
|
<div id="email-list" class="voicemail-list email-list">
|
||||||
|
<div class="queue-empty">No emails</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Chat -->
|
<!-- Chat -->
|
||||||
<section class="chat-section">
|
<section class="chat-section">
|
||||||
<div id="chat" class="chat-log"></div>
|
<div id="chat" class="chat-log"></div>
|
||||||
|
<div class="devon-bar">
|
||||||
|
<div class="devon-ask-row">
|
||||||
|
<input type="text" id="devon-input" placeholder="Ask Devon..." class="devon-input">
|
||||||
|
<button id="devon-ask-btn" class="devon-ask-btn">Ask <span class="shortcut-label">D</span></button>
|
||||||
|
<button id="devon-interject-btn" class="devon-interject-btn" title="Devon interjects on current conversation">Interject</button>
|
||||||
|
<label class="devon-monitor-label" title="Devon auto-monitors conversations">
|
||||||
|
<input type="checkbox" id="devon-monitor" checked> Monitor
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="devon-suggestion" class="devon-suggestion hidden">
|
||||||
|
<span class="devon-suggestion-text">Devon has something</span>
|
||||||
|
<button id="devon-play-btn" class="devon-play-btn">Play</button>
|
||||||
|
<button id="devon-dismiss-btn" class="devon-dismiss-btn">Dismiss</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="talk-controls">
|
<div class="talk-controls">
|
||||||
<button id="talk-btn" class="talk-btn">Hold to Talk</button>
|
<button id="talk-btn" class="talk-btn">Hold to Talk</button>
|
||||||
<button id="type-btn" class="type-btn">Type</button>
|
<button id="type-btn" class="type-btn">Type</button>
|
||||||
@@ -75,18 +138,18 @@
|
|||||||
<div id="status" class="status hidden"></div>
|
<div id="status" class="status hidden"></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Music -->
|
<!-- Music / Ads / Idents -->
|
||||||
|
<div class="media-row">
|
||||||
<section class="music-section">
|
<section class="music-section">
|
||||||
<h2>Music</h2>
|
<h2>Music</h2>
|
||||||
<select id="track-select"></select>
|
<select id="track-select"></select>
|
||||||
<div class="music-controls">
|
<div class="music-controls">
|
||||||
<button id="play-btn">Play</button>
|
<button id="play-btn">Play <span class="shortcut-label">M</span></button>
|
||||||
<button id="stop-btn">Stop</button>
|
<button id="stop-btn">Stop</button>
|
||||||
<input type="range" id="volume" min="0" max="100" value="30">
|
<input type="range" id="volume" min="0" max="100" value="30">
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Ads -->
|
|
||||||
<section class="music-section">
|
<section class="music-section">
|
||||||
<h2>Ads</h2>
|
<h2>Ads</h2>
|
||||||
<select id="ad-select"></select>
|
<select id="ad-select"></select>
|
||||||
@@ -96,6 +159,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="music-section">
|
||||||
|
<h2>Idents</h2>
|
||||||
|
<select id="ident-select"></select>
|
||||||
|
<div class="music-controls">
|
||||||
|
<button id="ident-play-btn">Play Ident</button>
|
||||||
|
<button id="ident-stop-btn">Stop</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Sound Effects -->
|
<!-- Sound Effects -->
|
||||||
<section class="sounds-section">
|
<section class="sounds-section">
|
||||||
<h2>Sounds</h2>
|
<h2>Sounds</h2>
|
||||||
@@ -107,6 +180,7 @@
|
|||||||
<div class="log-header">
|
<div class="log-header">
|
||||||
<h2>Server Log</h2>
|
<h2>Server Log</h2>
|
||||||
<div class="server-controls">
|
<div class="server-controls">
|
||||||
|
<button id="log-toggle-btn" class="log-toggle-btn">Show ▼</button>
|
||||||
<button id="restart-server-btn" class="server-btn restart">Restart</button>
|
<button id="restart-server-btn" class="server-btn restart">Restart</button>
|
||||||
<button id="stop-server-btn" class="server-btn stop">Stop</button>
|
<button id="stop-server-btn" class="server-btn stop">Stop</button>
|
||||||
<label class="auto-scroll-label">
|
<label class="auto-scroll-label">
|
||||||
@@ -114,7 +188,9 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="log-body collapsed">
|
||||||
<div id="server-log" class="server-log"></div>
|
<div id="server-log" class="server-log"></div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
@@ -125,7 +201,7 @@
|
|||||||
|
|
||||||
<!-- Audio Devices -->
|
<!-- Audio Devices -->
|
||||||
<div class="settings-group">
|
<div class="settings-group">
|
||||||
<h3>Audio Routing</h3>
|
<h3>Audio Devices</h3>
|
||||||
<div class="device-row">
|
<div class="device-row">
|
||||||
<label>
|
<label>
|
||||||
Input Device
|
Input Device
|
||||||
@@ -133,7 +209,7 @@
|
|||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Ch
|
Ch
|
||||||
<input type="number" id="input-channel" value="1" min="1" max="16" class="channel-input">
|
<input type="number" id="input-channel" value="1" min="1" max="32" class="channel-input">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="device-row">
|
<div class="device-row">
|
||||||
@@ -142,43 +218,70 @@
|
|||||||
<select id="output-device"></select>
|
<select id="output-device"></select>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="channel-row">
|
</div>
|
||||||
<label>Caller Ch <input type="number" id="caller-channel" value="3" min="1" max="16" class="channel-input"></label>
|
|
||||||
<label>Live Ch <input type="number" id="live-caller-channel" value="9" min="1" max="16" class="channel-input"></label>
|
<div class="settings-group">
|
||||||
<label>Music Ch <input type="number" id="music-channel" value="5" min="1" max="16" class="channel-input"></label>
|
<h3>Output Routing</h3>
|
||||||
<label>SFX Ch <input type="number" id="sfx-channel" value="7" min="1" max="16" class="channel-input"></label>
|
<div class="routing-grid">
|
||||||
<label>Ad Ch <input type="number" id="ad-channel" value="11" min="1" max="16" class="channel-input"></label>
|
<div class="routing-item">
|
||||||
|
<span class="routing-label">AI Caller</span>
|
||||||
|
<input type="number" id="caller-channel" value="3" min="1" max="32" class="channel-input">
|
||||||
|
</div>
|
||||||
|
<div class="routing-item">
|
||||||
|
<span class="routing-label">Devon</span>
|
||||||
|
<input type="number" id="devon-channel" value="17" min="1" max="32" class="channel-input">
|
||||||
|
</div>
|
||||||
|
<div class="routing-item">
|
||||||
|
<span class="routing-label">Live Caller</span>
|
||||||
|
<input type="number" id="live-caller-channel" value="9" min="1" max="32" class="channel-input">
|
||||||
|
</div>
|
||||||
|
<div class="routing-item">
|
||||||
|
<span class="routing-label">Music</span>
|
||||||
|
<input type="number" id="music-channel" value="5" min="1" max="32" class="channel-input">
|
||||||
|
</div>
|
||||||
|
<div class="routing-item">
|
||||||
|
<span class="routing-label">SFX</span>
|
||||||
|
<input type="number" id="sfx-channel" value="7" min="1" max="32" class="channel-input">
|
||||||
|
</div>
|
||||||
|
<div class="routing-item">
|
||||||
|
<span class="routing-label">Ads</span>
|
||||||
|
<input type="number" id="ad-channel" value="11" min="1" max="32" class="channel-input">
|
||||||
|
</div>
|
||||||
|
<div class="routing-item">
|
||||||
|
<span class="routing-label">Idents</span>
|
||||||
|
<input type="number" id="ident-channel" value="15" min="1" max="32" class="channel-input">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- LLM Settings -->
|
<!-- LLM Settings -->
|
||||||
<div class="settings-group">
|
<div class="settings-group">
|
||||||
<h3>LLM Provider</h3>
|
<h3>LLM Model Routing</h3>
|
||||||
<label>
|
<div class="model-routing-grid">
|
||||||
Provider
|
<div class="model-routing-item">
|
||||||
<select id="provider">
|
<span class="model-routing-label">Caller Dialog</span>
|
||||||
<option value="openrouter">OpenRouter</option>
|
<select id="model-caller_dialog" class="model-select"></select>
|
||||||
<option value="ollama">Ollama</option>
|
</div>
|
||||||
</select>
|
<div class="model-routing-item">
|
||||||
</label>
|
<span class="model-routing-label">Devon Monitor</span>
|
||||||
|
<select id="model-devon_monitor" class="model-select"></select>
|
||||||
<div id="openrouter-settings">
|
</div>
|
||||||
<label>
|
<div class="model-routing-item">
|
||||||
Model
|
<span class="model-routing-label">Devon Ask</span>
|
||||||
<select id="openrouter-model"></select>
|
<select id="model-devon_ask" class="model-select"></select>
|
||||||
</label>
|
</div>
|
||||||
|
<div class="model-routing-item">
|
||||||
|
<span class="model-routing-label">Backgrounds</span>
|
||||||
|
<select id="model-background_gen" class="model-select"></select>
|
||||||
|
</div>
|
||||||
|
<div class="model-routing-item">
|
||||||
|
<span class="model-routing-label">Call Summary</span>
|
||||||
|
<select id="model-call_summary" class="model-select"></select>
|
||||||
|
</div>
|
||||||
|
<div class="model-routing-item">
|
||||||
|
<span class="model-routing-label">News</span>
|
||||||
|
<select id="model-news_summary" class="model-select"></select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="ollama-settings" class="hidden">
|
|
||||||
<label>
|
|
||||||
Model
|
|
||||||
<select id="ollama-model"></select>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Host
|
|
||||||
<input type="text" id="ollama-host" value="http://localhost:11434">
|
|
||||||
</label>
|
|
||||||
<button type="button" id="refresh-ollama" class="refresh-btn">Refresh Models</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -224,6 +327,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/app.js?v=15"></script>
|
<script src="/js/app.js?v=22"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -0,0 +1,271 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Generate social media announcement images for Luke at the Roost.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python make_social_post.py # regenerate with defaults
|
||||||
|
python make_social_post.py --title "NEW FEATURE" # custom title
|
||||||
|
python make_social_post.py --body body_text.txt # body from file
|
||||||
|
|
||||||
|
Outputs square (1080x1080) and landscape (1200x675) PNGs to social_posts/.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import textwrap
|
||||||
|
from PIL import Image, ImageDraw, ImageFont, ImageOps
|
||||||
|
|
||||||
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
COVER = os.path.join(SCRIPT_DIR, "website/images/cover.png")
|
||||||
|
OUT_DIR = os.path.join(SCRIPT_DIR, "social_posts")
|
||||||
|
|
||||||
|
# Brand colors
|
||||||
|
BG = (18, 13, 7)
|
||||||
|
ACCENT = (232, 121, 29)
|
||||||
|
WHITE = (255, 255, 255)
|
||||||
|
MUTED = (175, 165, 150)
|
||||||
|
LIGHTER = (220, 215, 205)
|
||||||
|
|
||||||
|
# macOS system fonts — swap these on Linux/Windows
|
||||||
|
FONT_BLACK = "/System/Library/Fonts/Supplemental/Arial Black.ttf"
|
||||||
|
FONT_BOLD = "/System/Library/Fonts/Supplemental/Arial Bold.ttf"
|
||||||
|
FONT_REG = "/System/Library/Fonts/Supplemental/Arial.ttf"
|
||||||
|
|
||||||
|
|
||||||
|
def load_font(path, size):
|
||||||
|
return ImageFont.truetype(path, size)
|
||||||
|
|
||||||
|
|
||||||
|
def text_bbox(draw, text, font):
|
||||||
|
bb = draw.textbbox((0, 0), text, font=font)
|
||||||
|
return bb[2] - bb[0], bb[3] - bb[1], bb[1] # width, height, y_offset
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_text(draw, text, x, y, max_w, font, fill, line_gap=10,
|
||||||
|
cover_right=None, cover_bottom=None):
|
||||||
|
"""Word-wrap text onto the image, narrowing lines that overlap the cover.
|
||||||
|
|
||||||
|
line_gap: fixed pixel gap between lines (not a multiplier).
|
||||||
|
Returns y just below the last line of text (no trailing gap)."""
|
||||||
|
words = text.split()
|
||||||
|
lines = []
|
||||||
|
cur = ""
|
||||||
|
cur_y = y
|
||||||
|
|
||||||
|
for word in words:
|
||||||
|
test = f"{cur} {word}".strip()
|
||||||
|
eff_w = max_w
|
||||||
|
if cover_right and cover_bottom and cur_y < cover_bottom:
|
||||||
|
eff_w = cover_right - x - 20
|
||||||
|
|
||||||
|
tw, th, _ = text_bbox(draw, test, font)
|
||||||
|
if tw > eff_w and cur:
|
||||||
|
lines.append((cur, cur_y))
|
||||||
|
_, lh, _ = text_bbox(draw, cur, font)
|
||||||
|
cur_y += lh + line_gap
|
||||||
|
cur = word
|
||||||
|
else:
|
||||||
|
cur = test
|
||||||
|
|
||||||
|
if cur:
|
||||||
|
lines.append((cur, cur_y))
|
||||||
|
_, lh, _ = text_bbox(draw, cur, font)
|
||||||
|
|
||||||
|
for line, ly in lines:
|
||||||
|
draw.text((x, ly), line, font=font, fill=fill)
|
||||||
|
|
||||||
|
return cur_y + lh # return y just past the last line's bottom
|
||||||
|
|
||||||
|
|
||||||
|
def center_text(draw, text, y, canvas_w, font, fill):
|
||||||
|
tw, th, _ = text_bbox(draw, text, font)
|
||||||
|
draw.text(((canvas_w - tw) // 2, y), text, font=font, fill=fill)
|
||||||
|
return y + th
|
||||||
|
|
||||||
|
|
||||||
|
def draw_email_box(draw, email, y, canvas_w, font):
|
||||||
|
tw, th, y_off = text_bbox(draw, email, font)
|
||||||
|
px, py = 22, 16
|
||||||
|
box_w = tw + px * 2
|
||||||
|
box_x = (canvas_w - box_w) // 2
|
||||||
|
draw.rounded_rectangle(
|
||||||
|
[box_x, y, box_x + box_w, y + th + py * 2],
|
||||||
|
radius=8, fill=(45, 30, 12), outline=ACCENT, width=2,
|
||||||
|
)
|
||||||
|
draw.text((box_x + px, y + py - y_off), email, font=font, fill=ACCENT)
|
||||||
|
return y + th + py * 2
|
||||||
|
|
||||||
|
|
||||||
|
def draw_accent_bars(draw, w, h, thickness):
|
||||||
|
draw.rectangle([0, 0, w, thickness], fill=ACCENT)
|
||||||
|
draw.rectangle([0, h - thickness, w, h], fill=ACCENT)
|
||||||
|
|
||||||
|
|
||||||
|
def paste_cover(img, x, y, size, radius):
|
||||||
|
cover = Image.open(COVER).resize((size, size), Image.LANCZOS)
|
||||||
|
mask = Image.new("L", (size, size), 0)
|
||||||
|
ImageDraw.Draw(mask).rounded_rectangle([0, 0, size, size], radius=radius, fill=255)
|
||||||
|
img.paste(cover, (x, y), mask)
|
||||||
|
|
||||||
|
|
||||||
|
def make_square(title, paragraphs, email, filename="email_announcement_square.png"):
|
||||||
|
W = 1080
|
||||||
|
img = Image.new("RGB", (W, W), BG)
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
draw_accent_bars(draw, W, W, 8)
|
||||||
|
|
||||||
|
# Cover image — top right
|
||||||
|
cover_size, cover_x, cover_y = 240, W - 290, 35
|
||||||
|
paste_cover(img, cover_x, cover_y, cover_size, 20)
|
||||||
|
cover_bottom = cover_y + cover_size + 15
|
||||||
|
|
||||||
|
m = 60
|
||||||
|
y = 40
|
||||||
|
tw_full = W - m * 2
|
||||||
|
|
||||||
|
# Header
|
||||||
|
draw.text((m, y), "LUKE AT THE ROOST", font=load_font(FONT_BOLD, 24), fill=ACCENT)
|
||||||
|
y += 30
|
||||||
|
tag = load_font(FONT_REG, 20)
|
||||||
|
draw.text((m, y), "Late-night call-in radio", font=tag, fill=MUTED)
|
||||||
|
draw.text((m, y + 26), "powered by AI", font=tag, fill=MUTED)
|
||||||
|
y += 75
|
||||||
|
|
||||||
|
# Consistent spacing constants
|
||||||
|
LINE_GAP = 12 # between lines within a block
|
||||||
|
SECTION_GAP = 32 # between sections (body→CTA, CTA→footer)
|
||||||
|
PARA_GAP = 26 # between body paragraphs
|
||||||
|
TITLE_GAP = 48 # between title and first body paragraph
|
||||||
|
|
||||||
|
# Title
|
||||||
|
y = wrap_text(draw, title, m, y, tw_full, load_font(FONT_BLACK, 72), WHITE,
|
||||||
|
line_gap=LINE_GAP, cover_right=cover_x, cover_bottom=cover_bottom)
|
||||||
|
y += TITLE_GAP
|
||||||
|
|
||||||
|
# Body paragraphs
|
||||||
|
body_font = load_font(FONT_REG, 32)
|
||||||
|
colors = [LIGHTER] + [MUTED] * (len(paragraphs) - 1)
|
||||||
|
for i, (para, color) in enumerate(zip(paragraphs, colors)):
|
||||||
|
cr = cover_x if y < cover_bottom else None
|
||||||
|
cb = cover_bottom if y < cover_bottom else None
|
||||||
|
y = wrap_text(draw, para, m, y, tw_full, body_font, color,
|
||||||
|
line_gap=LINE_GAP, cover_right=cr, cover_bottom=cb)
|
||||||
|
if i < len(paragraphs) - 1:
|
||||||
|
y += PARA_GAP
|
||||||
|
|
||||||
|
y += SECTION_GAP
|
||||||
|
|
||||||
|
# Email CTA
|
||||||
|
y = draw_email_box(draw, email, y, W, load_font(FONT_BOLD, 36))
|
||||||
|
y += SECTION_GAP
|
||||||
|
|
||||||
|
# Footer
|
||||||
|
y = center_text(draw, "New episodes drop daily. Be part of the next one.",
|
||||||
|
y, W, load_font(FONT_REG, 24), MUTED)
|
||||||
|
y += PARA_GAP
|
||||||
|
info = load_font(FONT_REG, 22)
|
||||||
|
center_text(draw, "lukeattheroost.com", y, W, info, ACCENT)
|
||||||
|
y += PARA_GAP
|
||||||
|
center_text(draw, "Spotify \u00b7 Apple Podcasts \u00b7 YouTube \u00b7 RSS",
|
||||||
|
y, W, info, MUTED)
|
||||||
|
|
||||||
|
os.makedirs(OUT_DIR, exist_ok=True)
|
||||||
|
img.save(os.path.join(OUT_DIR, filename), quality=95)
|
||||||
|
print(f"Square: {filename}")
|
||||||
|
|
||||||
|
|
||||||
|
def make_landscape(title, paragraphs, email, filename="email_announcement_twitter.png"):
|
||||||
|
TW, TH = 1200, 675
|
||||||
|
img = Image.new("RGB", (TW, TH), BG)
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
draw_accent_bars(draw, TW, TH, 6)
|
||||||
|
|
||||||
|
# Cover image — top right
|
||||||
|
cover_size, cover_x, cover_y = 180, TW - 220, 22
|
||||||
|
paste_cover(img, cover_x, cover_y, cover_size, 16)
|
||||||
|
cover_bottom = cover_y + cover_size + 10
|
||||||
|
|
||||||
|
m = 45
|
||||||
|
y = 25
|
||||||
|
tw_full = TW - m * 2
|
||||||
|
|
||||||
|
# Header
|
||||||
|
draw.text((m, y), "LUKE AT THE ROOST", font=load_font(FONT_BOLD, 20), fill=ACCENT)
|
||||||
|
y += 24
|
||||||
|
draw.text((m, y), "Late-night call-in radio powered by AI",
|
||||||
|
font=load_font(FONT_REG, 17), fill=MUTED)
|
||||||
|
y += 38
|
||||||
|
|
||||||
|
# Consistent spacing constants
|
||||||
|
LINE_GAP = 8 # between lines within a block
|
||||||
|
SECTION_GAP = 20 # between sections
|
||||||
|
PARA_GAP = 16 # between body paragraphs
|
||||||
|
TITLE_GAP = 32 # between title and first body paragraph
|
||||||
|
|
||||||
|
# Title
|
||||||
|
y = wrap_text(draw, title, m, y, tw_full, load_font(FONT_BLACK, 50), WHITE,
|
||||||
|
line_gap=LINE_GAP, cover_right=cover_x, cover_bottom=cover_bottom)
|
||||||
|
y += TITLE_GAP
|
||||||
|
|
||||||
|
# Body paragraphs
|
||||||
|
body_font = load_font(FONT_REG, 23)
|
||||||
|
colors = [LIGHTER] + [MUTED] * (len(paragraphs) - 1)
|
||||||
|
for i, (para, color) in enumerate(zip(paragraphs, colors)):
|
||||||
|
cr = cover_x if y < cover_bottom else None
|
||||||
|
cb = cover_bottom if y < cover_bottom else None
|
||||||
|
y = wrap_text(draw, para, m, y, tw_full, body_font, color,
|
||||||
|
line_gap=LINE_GAP, cover_right=cr, cover_bottom=cb)
|
||||||
|
if i < len(paragraphs) - 1:
|
||||||
|
y += PARA_GAP
|
||||||
|
|
||||||
|
y += SECTION_GAP
|
||||||
|
|
||||||
|
# Email CTA
|
||||||
|
y = draw_email_box(draw, email, y, TW, load_font(FONT_BOLD, 26))
|
||||||
|
y += SECTION_GAP
|
||||||
|
|
||||||
|
# Footer
|
||||||
|
y = center_text(draw, "New episodes drop daily. Be part of the next one.",
|
||||||
|
y, TW, load_font(FONT_REG, 19), MUTED)
|
||||||
|
y += PARA_GAP
|
||||||
|
center_text(draw, "lukeattheroost.com \u00b7 Spotify \u00b7 Apple Podcasts \u00b7 YouTube",
|
||||||
|
y, TW, load_font(FONT_REG, 17), (140, 132, 120))
|
||||||
|
|
||||||
|
os.makedirs(OUT_DIR, exist_ok=True)
|
||||||
|
img.save(os.path.join(OUT_DIR, filename), quality=95)
|
||||||
|
print(f"Landscape: {filename}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Default content ---
|
||||||
|
|
||||||
|
DEFAULT_TITLE = "NOW ACCEPTING LISTENER EMAILS"
|
||||||
|
DEFAULT_EMAIL = "submissions@lukeattheroost.com"
|
||||||
|
DEFAULT_PARAGRAPHS = [
|
||||||
|
"Got a story? A question? A hot take that\u2019s been eating at you since midnight? A confession you need to get off your chest? Send it to the show.",
|
||||||
|
"The best listener emails get read live on air during the next episode \u2014 either by Luke himself on the mic, or by one of his robot friends. Your words, on the show, heard by everyone tuning in.",
|
||||||
|
"Can\u2019t call 208-439-LUKE at 2 AM? Don\u2019t want to talk on the phone? Now you\u2019ve got another way to be part of the conversation. Write in anytime \u2014 day or night, long or short, serious or unhinged.",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Generate social media images")
|
||||||
|
parser.add_argument("--title", default=DEFAULT_TITLE)
|
||||||
|
parser.add_argument("--email", default=DEFAULT_EMAIL)
|
||||||
|
parser.add_argument("--body", help="Text file with paragraphs (blank-line separated)")
|
||||||
|
parser.add_argument("--prefix", default="email_announcement",
|
||||||
|
help="Output filename prefix")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.body:
|
||||||
|
with open(args.body) as f:
|
||||||
|
paragraphs = [p.strip() for p in f.read().split("\n\n") if p.strip()]
|
||||||
|
else:
|
||||||
|
paragraphs = DEFAULT_PARAGRAPHS
|
||||||
|
|
||||||
|
make_square(args.title, paragraphs, args.email,
|
||||||
|
filename=f"{args.prefix}_square.png")
|
||||||
|
make_landscape(args.title, paragraphs, args.email,
|
||||||
|
filename=f"{args.prefix}_twitter.png")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -22,6 +22,8 @@ import sys
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
load_dotenv(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env"))
|
||||||
|
|
||||||
YOUTUBE_PLAYLIST = "PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-"
|
YOUTUBE_PLAYLIST = "PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-"
|
||||||
APPLE_PODCAST_ID = "1875205848"
|
APPLE_PODCAST_ID = "1875205848"
|
||||||
@@ -33,9 +35,9 @@ DOCKER_BIN = "/share/CACHEDEV1_DATA/.qpkg/container-station/bin/docker"
|
|||||||
CASTOPOD_DB_CONTAINER = "castopod-mariadb-1"
|
CASTOPOD_DB_CONTAINER = "castopod-mariadb-1"
|
||||||
|
|
||||||
BUNNY_STORAGE_ZONE = "lukeattheroost"
|
BUNNY_STORAGE_ZONE = "lukeattheroost"
|
||||||
BUNNY_STORAGE_KEY = "92749cd3-85df-4cff-938fe35eb994-30f8-4cf2"
|
BUNNY_STORAGE_KEY = os.getenv("BUNNY_STORAGE_KEY", "")
|
||||||
BUNNY_STORAGE_REGION = "la"
|
BUNNY_STORAGE_REGION = "la"
|
||||||
BUNNY_ACCOUNT_KEY = "2865f279-297b-431a-ad18-0ccf1f8e4fa8cf636cea-3222-415a-84ed-56ee195c0530"
|
BUNNY_ACCOUNT_KEY = os.getenv("BUNNY_ACCOUNT_KEY", "")
|
||||||
|
|
||||||
|
|
||||||
def _find_ytdlp():
|
def _find_ytdlp():
|
||||||
@@ -243,13 +245,16 @@ def _run_db_query(sql):
|
|||||||
docker_bin = path
|
docker_bin = path
|
||||||
break
|
break
|
||||||
|
|
||||||
|
db_pass = os.getenv("CASTOPOD_DB_PASS", "")
|
||||||
if docker_bin:
|
if docker_bin:
|
||||||
cmd = [docker_bin, "exec", "-i", CASTOPOD_DB_CONTAINER,
|
# Pass password via MYSQL_PWD env var instead of command line (not visible in ps)
|
||||||
"mysql", "-u", "castopod", "-pBYtbFfk3ndeVabb26xb0UyKU", "castopod", "-N"]
|
cmd = [docker_bin, "exec", "-i", "-e", f"MYSQL_PWD={db_pass}",
|
||||||
|
CASTOPOD_DB_CONTAINER,
|
||||||
|
"mysql", "-u", "castopod", "castopod", "-N"]
|
||||||
else:
|
else:
|
||||||
cmd = [
|
cmd = [
|
||||||
"ssh", "-p", NAS_SSH_PORT, NAS_SSH,
|
"ssh", "-p", NAS_SSH_PORT, NAS_SSH,
|
||||||
f"{DOCKER_BIN} exec -i {CASTOPOD_DB_CONTAINER} mysql -u castopod -pBYtbFfk3ndeVabb26xb0UyKU castopod -N"
|
f"{DOCKER_BIN} exec -i -e MYSQL_PWD={db_pass} {CASTOPOD_DB_CONTAINER} mysql -u castopod castopod -N"
|
||||||
]
|
]
|
||||||
try:
|
try:
|
||||||
proc = subprocess.run(cmd, input=sql, capture_output=True, text=True, timeout=30)
|
proc = subprocess.run(cmd, input=sql, capture_output=True, text=True, timeout=30)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
Usage: python postprod.py recordings/2026-02-07_213000/ -o episode.mp3
|
Usage: python postprod.py recordings/2026-02-07_213000/ -o episode.mp3
|
||||||
|
|
||||||
Processes 5 aligned WAV stems (host, caller, music, sfx, ads) into a
|
Processes 6 aligned WAV stems (host, caller, music, sfx, ads, idents) into a
|
||||||
broadcast-ready MP3 with gap removal, voice compression, music ducking,
|
broadcast-ready MP3 with gap removal, voice compression, music ducking,
|
||||||
and loudness normalization.
|
and loudness normalization.
|
||||||
"""
|
"""
|
||||||
@@ -17,7 +17,7 @@ from pathlib import Path
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import soundfile as sf
|
import soundfile as sf
|
||||||
|
|
||||||
STEM_NAMES = ["host", "caller", "music", "sfx", "ads"]
|
STEM_NAMES = ["host", "caller", "devon", "music", "sfx", "ads", "idents"]
|
||||||
|
|
||||||
|
|
||||||
def load_stems(stems_dir: Path) -> tuple[dict[str, np.ndarray], int]:
|
def load_stems(stems_dir: Path) -> tuple[dict[str, np.ndarray], int]:
|
||||||
@@ -69,7 +69,7 @@ def remove_gaps(stems: dict[str, np.ndarray], sr: int,
|
|||||||
|
|
||||||
# Detect gaps in everything except music (which always plays).
|
# Detect gaps in everything except music (which always plays).
|
||||||
# This catches TTS latency gaps while protecting ad breaks and SFX transitions.
|
# This catches TTS latency gaps while protecting ad breaks and SFX transitions.
|
||||||
content = stems["host"] + stems["caller"] + stems["sfx"] + stems["ads"]
|
content = stems["host"] + stems["caller"] + stems["devon"] + stems["sfx"] + stems["ads"] + stems["idents"]
|
||||||
rms = compute_rms(content, window_samples)
|
rms = compute_rms(content, window_samples)
|
||||||
|
|
||||||
# Threshold: percentile-based to sit above the mic noise floor
|
# Threshold: percentile-based to sit above the mic noise floor
|
||||||
@@ -386,7 +386,7 @@ def apply_ducking(music: np.ndarray, dialog: np.ndarray, sr: int,
|
|||||||
|
|
||||||
def match_voice_levels(stems: dict[str, np.ndarray], target_rms: float = 0.1) -> dict[str, np.ndarray]:
|
def match_voice_levels(stems: dict[str, np.ndarray], target_rms: float = 0.1) -> dict[str, np.ndarray]:
|
||||||
"""Normalize host, caller, and ads stems to the same RMS level."""
|
"""Normalize host, caller, and ads stems to the same RMS level."""
|
||||||
for name in ["host", "caller", "ads"]:
|
for name in ["host", "caller", "ads", "idents"]:
|
||||||
audio = stems[name]
|
audio = stems[name]
|
||||||
# Only measure non-silent portions
|
# Only measure non-silent portions
|
||||||
active = audio[np.abs(audio) > 0.001]
|
active = audio[np.abs(audio) > 0.001]
|
||||||
@@ -408,7 +408,7 @@ def mix_stems(stems: dict[str, np.ndarray],
|
|||||||
levels: dict[str, float] | None = None,
|
levels: dict[str, float] | None = None,
|
||||||
stereo_imaging: bool = True) -> np.ndarray:
|
stereo_imaging: bool = True) -> np.ndarray:
|
||||||
if levels is None:
|
if levels is None:
|
||||||
levels = {"host": 0, "caller": 0, "music": -6, "sfx": -10, "ads": 0}
|
levels = {"host": 0, "caller": 0, "music": -6, "sfx": -10, "ads": 0, "idents": 0}
|
||||||
|
|
||||||
gains = {name: 10 ** (db / 20) for name, db in levels.items()}
|
gains = {name: 10 ** (db / 20) for name, db in levels.items()}
|
||||||
|
|
||||||
@@ -417,7 +417,7 @@ def mix_stems(stems: dict[str, np.ndarray],
|
|||||||
if stereo_imaging:
|
if stereo_imaging:
|
||||||
# Pan positions: -1.0 = full left, 0.0 = center, 1.0 = full right
|
# Pan positions: -1.0 = full left, 0.0 = center, 1.0 = full right
|
||||||
# Using constant-power panning law
|
# Using constant-power panning law
|
||||||
pans = {"host": 0.0, "caller": 0.15, "music": 0.0, "sfx": 0.0, "ads": 0.0}
|
pans = {"host": 0.0, "caller": 0.15, "music": 0.0, "sfx": 0.0, "ads": 0.0, "idents": 0.0}
|
||||||
# Music gets stereo width via slight L/R decorrelation
|
# Music gets stereo width via slight L/R decorrelation
|
||||||
music_width = 0.3
|
music_width = 0.3
|
||||||
|
|
||||||
@@ -432,7 +432,7 @@ def mix_stems(stems: dict[str, np.ndarray],
|
|||||||
|
|
||||||
if name == "music" and music_width > 0:
|
if name == "music" and music_width > 0:
|
||||||
# Widen music: delay right channel by ~0.5ms for Haas effect
|
# Widen music: delay right channel by ~0.5ms for Haas effect
|
||||||
delay_samples = int(0.0005 * 44100) # ~22 samples at 44.1kHz
|
delay_samples = int(0.0005 * sr) # ~22 samples at target sample rate
|
||||||
left += signal * (1 + music_width * 0.5)
|
left += signal * (1 + music_width * 0.5)
|
||||||
right_delayed = np.zeros_like(signal)
|
right_delayed = np.zeros_like(signal)
|
||||||
right_delayed[delay_samples:] = signal[:-delay_samples] if delay_samples > 0 else signal
|
right_delayed[delay_samples:] = signal[:-delay_samples] if delay_samples > 0 else signal
|
||||||
@@ -774,7 +774,7 @@ def main():
|
|||||||
print(f"\n[3/{total_steps}] Limiting ads + SFX...")
|
print(f"\n[3/{total_steps}] Limiting ads + SFX...")
|
||||||
with tempfile.TemporaryDirectory() as tmp:
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
tmp_dir = Path(tmp)
|
tmp_dir = Path(tmp)
|
||||||
for name in ["ads", "sfx"]:
|
for name in ["ads", "sfx", "idents"]:
|
||||||
if np.any(stems[name] != 0):
|
if np.any(stems[name] != 0):
|
||||||
stems[name] = limit_stem(stems[name], sr, tmp_dir, name)
|
stems[name] = limit_stem(stems[name], sr, tmp_dir, name)
|
||||||
|
|
||||||
@@ -834,7 +834,7 @@ def main():
|
|||||||
dialog = stems["host"] + stems["caller"]
|
dialog = stems["host"] + stems["caller"]
|
||||||
if np.any(dialog != 0) and np.any(stems["music"] != 0):
|
if np.any(dialog != 0) and np.any(stems["music"] != 0):
|
||||||
stems["music"] = apply_ducking(stems["music"], dialog, sr, duck_db=args.duck_amount,
|
stems["music"] = apply_ducking(stems["music"], dialog, sr, duck_db=args.duck_amount,
|
||||||
mute_signal=stems["ads"])
|
mute_signal=stems["ads"] + stems["idents"])
|
||||||
print(" Applied")
|
print(" Applied")
|
||||||
else:
|
else:
|
||||||
print(" No dialog or music to duck")
|
print(" No dialog or music to duck")
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
-- Show Region Marker — background script for REAPER
|
||||||
|
-- Polls /tmp/reaper_state.txt for state changes and creates colored regions.
|
||||||
|
-- Backend writes "dialog", "ad", or "ident" to the file.
|
||||||
|
-- Run via Actions → Run ReaScript before or during recording.
|
||||||
|
|
||||||
|
local STATE_FILE = "/tmp/reaper_state.txt"
|
||||||
|
|
||||||
|
local COLORS = {
|
||||||
|
dialog = reaper.ColorToNative(50, 180, 50) + 0x1000000, -- green
|
||||||
|
ad = reaper.ColorToNative(200, 80, 80) + 0x1000000, -- red
|
||||||
|
ident = reaper.ColorToNative(80, 120, 200) + 0x1000000, -- blue
|
||||||
|
}
|
||||||
|
local LABELS = {
|
||||||
|
dialog = "DIALOG",
|
||||||
|
ad = "AD",
|
||||||
|
ident = "IDENT",
|
||||||
|
}
|
||||||
|
|
||||||
|
local counts = { dialog = 0, ad = 0, ident = 0 }
|
||||||
|
local current_type = nil -- which region type is currently open
|
||||||
|
local current_start = 0
|
||||||
|
local last_pos = 0 -- last known transport position (while running)
|
||||||
|
local last_state = ""
|
||||||
|
local transport_active = false
|
||||||
|
|
||||||
|
local function log(msg)
|
||||||
|
reaper.ShowConsoleMsg("[Regions] " .. msg .. "\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function is_playing_or_recording()
|
||||||
|
local state = reaper.GetPlayState()
|
||||||
|
return state > 0 and state ~= 2
|
||||||
|
end
|
||||||
|
|
||||||
|
local function open_region(rtype)
|
||||||
|
if current_type then return end
|
||||||
|
current_type = rtype
|
||||||
|
current_start = reaper.GetPlayPosition()
|
||||||
|
log("OPEN " .. rtype .. " at " .. string.format("%.2f", current_start))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function close_region(pos_override)
|
||||||
|
if not current_type then return end
|
||||||
|
local pos = pos_override or reaper.GetPlayPosition()
|
||||||
|
local len = pos - current_start
|
||||||
|
local rtype = current_type
|
||||||
|
current_type = nil
|
||||||
|
log("CLOSE " .. rtype .. " at " .. string.format("%.2f", pos) .. " (len=" .. string.format("%.2f", len) .. ")")
|
||||||
|
if len > 0.1 then
|
||||||
|
counts[rtype] = counts[rtype] + 1
|
||||||
|
local name = LABELS[rtype] .. " " .. counts[rtype]
|
||||||
|
reaper.AddProjectMarker2(0, true, current_start, pos, name, -1, COLORS[rtype])
|
||||||
|
log(" -> Created '" .. name .. "'")
|
||||||
|
else
|
||||||
|
log(" -> Skipped (too short)")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function poll()
|
||||||
|
if not transport_active then
|
||||||
|
if is_playing_or_recording() then
|
||||||
|
transport_active = true
|
||||||
|
log("Transport started at " .. string.format("%.2f", reaper.GetPlayPosition()))
|
||||||
|
local f = io.open(STATE_FILE, "r")
|
||||||
|
if f then
|
||||||
|
last_state = f:read("*l") or "dialog"
|
||||||
|
f:close()
|
||||||
|
else
|
||||||
|
last_state = "dialog"
|
||||||
|
end
|
||||||
|
log("Initial state: '" .. last_state .. "'")
|
||||||
|
open_region(last_state)
|
||||||
|
end
|
||||||
|
reaper.defer(poll)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Track position while transport is running
|
||||||
|
last_pos = reaper.GetPlayPosition()
|
||||||
|
|
||||||
|
-- Detect transport stop (recording ended) — use last known good position
|
||||||
|
if not is_playing_or_recording() then
|
||||||
|
log("Transport stopped at last known pos " .. string.format("%.2f", last_pos))
|
||||||
|
close_region(last_pos)
|
||||||
|
transport_active = false
|
||||||
|
reaper.defer(poll)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local f = io.open(STATE_FILE, "r")
|
||||||
|
if f then
|
||||||
|
local state = f:read("*l") or "dialog"
|
||||||
|
f:close()
|
||||||
|
|
||||||
|
if state ~= last_state then
|
||||||
|
log("State change: '" .. last_state .. "' -> '" .. state .. "'")
|
||||||
|
close_region()
|
||||||
|
open_region(state)
|
||||||
|
last_state = state
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
reaper.defer(poll)
|
||||||
|
end
|
||||||
|
|
||||||
|
log("Script loaded — waiting for transport to start...")
|
||||||
|
|
||||||
|
reaper.atexit(function()
|
||||||
|
log("Script stopping (atexit)")
|
||||||
|
close_region()
|
||||||
|
local total = counts.dialog + counts.ad + counts.ident
|
||||||
|
log("Done. " .. total .. " regions (" .. counts.dialog .. " dialog, " .. counts.ad .. " ad, " .. counts.ident .. " ident)")
|
||||||
|
end)
|
||||||
|
|
||||||
|
poll()
|
||||||
@@ -0,0 +1,772 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Upload podcast clips to social media (direct YouTube & Bluesky, Postiz for others).
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python upload_clips.py # interactive: pick episode, clips, platforms
|
||||||
|
python upload_clips.py clips/episode-12/ # pick clips and platforms interactively
|
||||||
|
python upload_clips.py clips/episode-12/ --clip 1 --platforms ig,yt
|
||||||
|
python upload_clips.py clips/episode-12/ --yes # skip all prompts, upload everything
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from atproto import Client as BskyClient
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
|
||||||
|
load_dotenv(Path(__file__).parent / ".env")
|
||||||
|
|
||||||
|
POSTIZ_API_KEY = os.getenv("POSTIZ_API_KEY")
|
||||||
|
POSTIZ_URL = os.getenv("POSTIZ_URL", "https://social.lukeattheroost.com")
|
||||||
|
|
||||||
|
BSKY_HANDLE = os.getenv("BSKY_HANDLE", "lukeattheroost.bsky.social")
|
||||||
|
BSKY_APP_PASSWORD = os.getenv("BSKY_APP_PASSWORD")
|
||||||
|
|
||||||
|
YT_CLIENT_SECRETS = Path(__file__).parent / "youtube_client_secrets.json"
|
||||||
|
YT_TOKEN_FILE = Path(__file__).parent / "youtube_token.json"
|
||||||
|
|
||||||
|
PLATFORM_ALIASES = {
|
||||||
|
"ig": "instagram", "insta": "instagram", "instagram": "instagram",
|
||||||
|
"yt": "youtube", "youtube": "youtube",
|
||||||
|
"fb": "facebook", "facebook": "facebook",
|
||||||
|
"bsky": "bluesky", "bluesky": "bluesky",
|
||||||
|
"masto": "mastodon", "mastodon": "mastodon",
|
||||||
|
"nostr": "nostr",
|
||||||
|
"li": "linkedin", "linkedin": "linkedin",
|
||||||
|
"threads": "threads",
|
||||||
|
"tt": "tiktok", "tiktok": "tiktok",
|
||||||
|
}
|
||||||
|
|
||||||
|
PLATFORM_DISPLAY = {
|
||||||
|
"instagram": "Instagram Reels",
|
||||||
|
"youtube": "YouTube Shorts",
|
||||||
|
"facebook": "Facebook Reels",
|
||||||
|
"bluesky": "Bluesky",
|
||||||
|
"mastodon": "Mastodon",
|
||||||
|
"nostr": "Nostr",
|
||||||
|
"linkedin": "LinkedIn",
|
||||||
|
"threads": "Threads",
|
||||||
|
"tiktok": "TikTok",
|
||||||
|
}
|
||||||
|
|
||||||
|
ALL_PLATFORMS = list(PLATFORM_DISPLAY.keys())
|
||||||
|
|
||||||
|
UPLOAD_LEDGER_FILE = "upload-history.json"
|
||||||
|
|
||||||
|
|
||||||
|
def load_upload_history(clips_dir: Path) -> dict:
|
||||||
|
"""Load upload history for a clips directory.
|
||||||
|
Returns dict mapping clip_file -> list of platforms already uploaded to.
|
||||||
|
"""
|
||||||
|
ledger = clips_dir / UPLOAD_LEDGER_FILE
|
||||||
|
if ledger.exists():
|
||||||
|
with open(ledger) as f:
|
||||||
|
return json.load(f)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def save_upload_history(clips_dir: Path, history: dict):
|
||||||
|
with open(clips_dir / UPLOAD_LEDGER_FILE, "w") as f:
|
||||||
|
json.dump(history, f, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
def get_api_url(path: str) -> str:
|
||||||
|
base = POSTIZ_URL.rstrip("/")
|
||||||
|
return f"{base}/api/public/v1{path}"
|
||||||
|
|
||||||
|
|
||||||
|
def api_headers() -> dict:
|
||||||
|
return {
|
||||||
|
"Authorization": POSTIZ_API_KEY,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_integrations() -> list[dict]:
|
||||||
|
resp = requests.get(get_api_url("/integrations"), headers=api_headers(), timeout=15)
|
||||||
|
if resp.status_code != 200:
|
||||||
|
print(f"Error fetching integrations: {resp.status_code} {resp.text[:200]}")
|
||||||
|
sys.exit(1)
|
||||||
|
return resp.json()
|
||||||
|
|
||||||
|
|
||||||
|
def find_integration(integrations: list[dict], provider: str) -> dict | None:
|
||||||
|
for integ in integrations:
|
||||||
|
if integ.get("identifier", "").startswith(provider) and not integ.get("disabled"):
|
||||||
|
return integ
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def upload_file(file_path: Path) -> dict:
|
||||||
|
headers = {"Authorization": POSTIZ_API_KEY}
|
||||||
|
with open(file_path, "rb") as f:
|
||||||
|
resp = requests.post(
|
||||||
|
get_api_url("/upload"),
|
||||||
|
headers=headers,
|
||||||
|
files={"file": (file_path.name, f, "video/mp4")},
|
||||||
|
timeout=120,
|
||||||
|
)
|
||||||
|
if resp.status_code not in (200, 201):
|
||||||
|
print(f"Upload failed: {resp.status_code} {resp.text[:200]}")
|
||||||
|
return {}
|
||||||
|
return resp.json()
|
||||||
|
|
||||||
|
|
||||||
|
def build_content(clip: dict, platform: str) -> str:
|
||||||
|
desc = clip.get("description", clip.get("caption_text", ""))
|
||||||
|
hashtags = clip.get("hashtags", [])
|
||||||
|
hashtag_str = " ".join(hashtags)
|
||||||
|
|
||||||
|
if platform == "bluesky":
|
||||||
|
if hashtags and len(desc) + 2 + len(hashtag_str) <= 300:
|
||||||
|
return desc + "\n\n" + hashtag_str
|
||||||
|
return desc[:300]
|
||||||
|
|
||||||
|
parts = [desc]
|
||||||
|
if hashtags:
|
||||||
|
parts.append("\n\n" + hashtag_str)
|
||||||
|
if platform in ("youtube", "facebook"):
|
||||||
|
parts.append("\n\nListen to the full episode: lukeattheroost.com")
|
||||||
|
return "".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
def build_settings(clip: dict, platform: str) -> dict:
|
||||||
|
if platform == "instagram":
|
||||||
|
return {"__type": "instagram", "post_type": "post", "collaborators": []}
|
||||||
|
if platform == "youtube":
|
||||||
|
yt_tags = [{"value": h.lstrip("#"), "label": h.lstrip("#")}
|
||||||
|
for h in clip.get("hashtags", [])]
|
||||||
|
return {
|
||||||
|
"__type": "youtube",
|
||||||
|
"title": clip["title"],
|
||||||
|
"type": "public",
|
||||||
|
"selfDeclaredMadeForKids": "no",
|
||||||
|
"thumbnail": None,
|
||||||
|
"tags": yt_tags,
|
||||||
|
}
|
||||||
|
if platform == "tiktok":
|
||||||
|
return {
|
||||||
|
"__type": "tiktok",
|
||||||
|
"privacy_level": "PUBLIC_TO_EVERYONE",
|
||||||
|
"duet": False,
|
||||||
|
"stitch": False,
|
||||||
|
"comment": True,
|
||||||
|
"autoAddMusic": "no",
|
||||||
|
"brand_content_toggle": False,
|
||||||
|
"brand_organic_toggle": False,
|
||||||
|
"content_posting_method": "DIRECT_POST",
|
||||||
|
}
|
||||||
|
return {"__type": platform}
|
||||||
|
|
||||||
|
|
||||||
|
def post_to_bluesky(clip: dict, clip_file: Path) -> bool:
|
||||||
|
"""Post a clip directly to Bluesky via atproto (bypasses Postiz)."""
|
||||||
|
import time
|
||||||
|
import httpx
|
||||||
|
from atproto import models
|
||||||
|
|
||||||
|
if not BSKY_APP_PASSWORD:
|
||||||
|
print(" Error: BSKY_APP_PASSWORD not set in .env")
|
||||||
|
return False
|
||||||
|
|
||||||
|
client = BskyClient()
|
||||||
|
client.login(BSKY_HANDLE, BSKY_APP_PASSWORD)
|
||||||
|
did = client.me.did
|
||||||
|
video_data = clip_file.read_bytes()
|
||||||
|
|
||||||
|
# Get a service auth token scoped to the user's PDS (required by video service)
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
pds_host = urlparse(client._session.pds_endpoint).hostname
|
||||||
|
service_auth = client.com.atproto.server.get_service_auth(
|
||||||
|
{"aud": f"did:web:{pds_host}", "lxm": "com.atproto.repo.uploadBlob"}
|
||||||
|
)
|
||||||
|
token = service_auth.token
|
||||||
|
|
||||||
|
# Upload video to Bluesky's video processing service (not the PDS)
|
||||||
|
print(f" Uploading video ({len(video_data) / 1_000_000:.1f} MB)...")
|
||||||
|
upload_resp = httpx.post(
|
||||||
|
"https://video.bsky.app/xrpc/app.bsky.video.uploadVideo",
|
||||||
|
params={"did": did, "name": clip_file.name},
|
||||||
|
headers={
|
||||||
|
"Authorization": f"Bearer {token}",
|
||||||
|
"Content-Type": "video/mp4",
|
||||||
|
},
|
||||||
|
content=video_data,
|
||||||
|
timeout=120,
|
||||||
|
)
|
||||||
|
if upload_resp.status_code not in (200, 409):
|
||||||
|
print(f" Upload failed: {upload_resp.status_code} {upload_resp.text[:200]}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
upload_data = upload_resp.json()
|
||||||
|
job_id = upload_data.get("jobId") or upload_data.get("jobStatus", {}).get("jobId")
|
||||||
|
if not job_id:
|
||||||
|
print(f" No jobId returned: {upload_resp.text[:200]}")
|
||||||
|
return False
|
||||||
|
print(f" Video processing (job {job_id})...")
|
||||||
|
|
||||||
|
# Poll until video is processed
|
||||||
|
session_token = client._session.access_jwt
|
||||||
|
blob = None
|
||||||
|
while True:
|
||||||
|
status_resp = httpx.get(
|
||||||
|
"https://video.bsky.app/xrpc/app.bsky.video.getJobStatus",
|
||||||
|
params={"jobId": job_id},
|
||||||
|
headers={"Authorization": f"Bearer {session_token}"},
|
||||||
|
timeout=15,
|
||||||
|
)
|
||||||
|
resp_data = status_resp.json()
|
||||||
|
status = resp_data.get("jobStatus") or resp_data
|
||||||
|
state = status.get("state")
|
||||||
|
if state == "JOB_STATE_COMPLETED":
|
||||||
|
blob = status.get("blob")
|
||||||
|
break
|
||||||
|
if state == "JOB_STATE_FAILED":
|
||||||
|
err = status.get("error") or status.get("message") or "unknown"
|
||||||
|
print(f" Video processing failed: {err}")
|
||||||
|
return False
|
||||||
|
progress = status.get("progress", 0)
|
||||||
|
print(f" Processing... {progress}%")
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
if not blob:
|
||||||
|
print(" No blob returned after processing")
|
||||||
|
return False
|
||||||
|
|
||||||
|
text = build_content(clip, "bluesky")
|
||||||
|
|
||||||
|
embed = models.AppBskyEmbedVideo.Main(
|
||||||
|
video=models.blob_ref.BlobRef(
|
||||||
|
mime_type=blob["mimeType"],
|
||||||
|
size=blob["size"],
|
||||||
|
ref=models.blob_ref.IpldLink(link=blob["ref"]["$link"]),
|
||||||
|
),
|
||||||
|
alt=clip.get("caption_text", clip["title"]),
|
||||||
|
aspect_ratio=models.AppBskyEmbedDefs.AspectRatio(width=1080, height=1920),
|
||||||
|
)
|
||||||
|
client.send_post(text=text, embed=embed)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_youtube_service():
|
||||||
|
"""Authenticate with YouTube API. First run opens a browser, then reuses saved token."""
|
||||||
|
from google.oauth2.credentials import Credentials
|
||||||
|
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||||
|
from google.auth.transport.requests import Request
|
||||||
|
from googleapiclient.discovery import build as yt_build
|
||||||
|
|
||||||
|
scopes = ["https://www.googleapis.com/auth/youtube.upload"]
|
||||||
|
creds = None
|
||||||
|
|
||||||
|
if YT_TOKEN_FILE.exists():
|
||||||
|
creds = Credentials.from_authorized_user_file(str(YT_TOKEN_FILE), scopes)
|
||||||
|
|
||||||
|
if not creds or not creds.valid:
|
||||||
|
if creds and creds.expired and creds.refresh_token:
|
||||||
|
creds.refresh(Request())
|
||||||
|
else:
|
||||||
|
if not YT_CLIENT_SECRETS.exists():
|
||||||
|
print(" Error: youtube_client_secrets.json not found")
|
||||||
|
print(" Download OAuth2 Desktop App credentials from Google Cloud Console")
|
||||||
|
return None
|
||||||
|
flow = InstalledAppFlow.from_client_secrets_file(str(YT_CLIENT_SECRETS), scopes)
|
||||||
|
creds = flow.run_local_server(port=8090)
|
||||||
|
|
||||||
|
with open(YT_TOKEN_FILE, "w") as f:
|
||||||
|
f.write(creds.to_json())
|
||||||
|
|
||||||
|
return yt_build("youtube", "v3", credentials=creds)
|
||||||
|
|
||||||
|
|
||||||
|
def post_to_youtube(clip: dict, clip_file: Path) -> bool:
|
||||||
|
"""Upload a clip directly to YouTube Shorts via the Data API."""
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
from googleapiclient.http import MediaFileUpload
|
||||||
|
from googleapiclient.errors import HttpError
|
||||||
|
|
||||||
|
youtube = get_youtube_service()
|
||||||
|
if not youtube:
|
||||||
|
return False
|
||||||
|
|
||||||
|
title = clip["title"]
|
||||||
|
if "#Shorts" not in title:
|
||||||
|
title = f"{title} #Shorts"
|
||||||
|
|
||||||
|
description = build_content(clip, "youtube")
|
||||||
|
if "#Shorts" not in description:
|
||||||
|
description += "\n\n#Shorts"
|
||||||
|
|
||||||
|
tags = [h.lstrip("#") for h in clip.get("hashtags", [])]
|
||||||
|
if "Shorts" not in tags:
|
||||||
|
tags.insert(0, "Shorts")
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"snippet": {
|
||||||
|
"title": title[:100],
|
||||||
|
"description": description,
|
||||||
|
"tags": tags,
|
||||||
|
"categoryId": "24", # Entertainment
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"privacyStatus": "public",
|
||||||
|
"selfDeclaredMadeForKids": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
media = MediaFileUpload(
|
||||||
|
str(clip_file),
|
||||||
|
mimetype="video/mp4",
|
||||||
|
chunksize=256 * 1024,
|
||||||
|
resumable=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
request = youtube.videos().insert(part="snippet,status", body=body, media_body=media)
|
||||||
|
|
||||||
|
file_size = clip_file.stat().st_size / 1_000_000
|
||||||
|
print(f" Uploading video ({file_size:.1f} MB)...")
|
||||||
|
|
||||||
|
response = None
|
||||||
|
retry = 0
|
||||||
|
while response is None:
|
||||||
|
try:
|
||||||
|
status, response = request.next_chunk()
|
||||||
|
if status:
|
||||||
|
print(f" Upload {int(status.progress() * 100)}%...")
|
||||||
|
except HttpError as e:
|
||||||
|
if e.resp.status in (500, 502, 503, 504) and retry < 5:
|
||||||
|
retry += 1
|
||||||
|
wait = random.random() * (2 ** retry)
|
||||||
|
print(f" Retrying in {wait:.1f}s...")
|
||||||
|
time.sleep(wait)
|
||||||
|
else:
|
||||||
|
print(f" YouTube API error: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
video_id = response["id"]
|
||||||
|
print(f" https://youtube.com/shorts/{video_id}")
|
||||||
|
return video_id
|
||||||
|
|
||||||
|
|
||||||
|
def create_post(integration_id: str, content: str, media: dict,
|
||||||
|
settings: dict, schedule: str | None = None) -> dict:
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
post_type = "schedule" if schedule else "now"
|
||||||
|
date = schedule or datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z")
|
||||||
|
payload = {
|
||||||
|
"type": post_type,
|
||||||
|
"date": date,
|
||||||
|
"shortLink": False,
|
||||||
|
"tags": [],
|
||||||
|
"posts": [
|
||||||
|
{
|
||||||
|
"integration": {"id": integration_id},
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"content": content,
|
||||||
|
"image": [media] if media else [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": settings,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = requests.post(
|
||||||
|
get_api_url("/posts"),
|
||||||
|
headers=api_headers(),
|
||||||
|
json=payload,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
if resp.status_code not in (200, 201):
|
||||||
|
print(f"Post creation failed: {resp.status_code} {resp.text[:300]}")
|
||||||
|
return {}
|
||||||
|
return resp.json()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
valid_names = sorted(set(PLATFORM_ALIASES.keys()))
|
||||||
|
parser = argparse.ArgumentParser(description="Upload podcast clips to social media via Postiz")
|
||||||
|
parser.add_argument("clips_dir", nargs="?", help="Path to clips directory (e.g. clips/episode-12/). If omitted, shows a picker.")
|
||||||
|
parser.add_argument("--clip", "-c", type=int, help="Upload only clip N (1-indexed)")
|
||||||
|
parser.add_argument("--platforms", "-p",
|
||||||
|
help=f"Comma-separated platforms ({','.join(ALL_PLATFORMS)}). Default: all")
|
||||||
|
parser.add_argument("--schedule", "-s", help="Schedule time (ISO 8601, e.g. 2026-02-16T10:00:00)")
|
||||||
|
parser.add_argument("--yes", "-y", action="store_true", help="Skip confirmation prompt")
|
||||||
|
parser.add_argument("--dry-run", action="store_true", help="Show what would be uploaded without posting")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not POSTIZ_API_KEY:
|
||||||
|
print("Error: POSTIZ_API_KEY not set in .env")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Resolve clips directory — pick interactively if not provided
|
||||||
|
if args.clips_dir:
|
||||||
|
clips_dir = Path(args.clips_dir).expanduser().resolve()
|
||||||
|
else:
|
||||||
|
clips_root = Path(__file__).parent / "clips"
|
||||||
|
episode_dirs = sorted(
|
||||||
|
[d for d in clips_root.iterdir()
|
||||||
|
if d.is_dir() and not d.name.startswith(".") and (d / "clips-metadata.json").exists()],
|
||||||
|
key=lambda d: (int(m.group(1)) if (m := re.search(r'(\d+)', d.name)) else 0, d.name),
|
||||||
|
)
|
||||||
|
if not episode_dirs:
|
||||||
|
print("No clip directories found in clips/. Run make_clips.py first.")
|
||||||
|
sys.exit(1)
|
||||||
|
print("\nAvailable episodes:\n")
|
||||||
|
for i, d in enumerate(episode_dirs):
|
||||||
|
with open(d / "clips-metadata.json") as f:
|
||||||
|
meta = json.load(f)
|
||||||
|
print(f" {i+1}. {d.name} ({len(meta)} clip{'s' if len(meta) != 1 else ''})")
|
||||||
|
print()
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
choice = input("Which episode? ").strip()
|
||||||
|
idx = int(choice) - 1
|
||||||
|
if 0 <= idx < len(episode_dirs):
|
||||||
|
clips_dir = episode_dirs[idx]
|
||||||
|
break
|
||||||
|
print(f" Enter 1-{len(episode_dirs)}")
|
||||||
|
except (ValueError, EOFError):
|
||||||
|
print(f" Enter an episode number")
|
||||||
|
|
||||||
|
metadata_path = clips_dir / "clips-metadata.json"
|
||||||
|
if not metadata_path.exists():
|
||||||
|
print(f"Error: No clips-metadata.json found in {clips_dir}")
|
||||||
|
print("Run make_clips.py first to generate clips and metadata.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(metadata_path) as f:
|
||||||
|
clips = json.load(f)
|
||||||
|
|
||||||
|
# Pick clips
|
||||||
|
if args.clip:
|
||||||
|
if args.clip < 1 or args.clip > len(clips):
|
||||||
|
print(f"Error: Clip {args.clip} not found (have {len(clips)} clips)")
|
||||||
|
sys.exit(1)
|
||||||
|
clips = [clips[args.clip - 1]]
|
||||||
|
elif not args.yes:
|
||||||
|
print(f"\nFound {len(clips)} clip(s):\n")
|
||||||
|
for i, clip in enumerate(clips):
|
||||||
|
desc = clip.get('description', clip.get('caption_text', ''))
|
||||||
|
if len(desc) > 70:
|
||||||
|
desc = desc[:desc.rfind(' ', 0, 70)] + '...'
|
||||||
|
print(f" {i+1}. \"{clip['title']}\" ({clip['duration']:.0f}s)")
|
||||||
|
print(f" {desc}")
|
||||||
|
print(f"\n a. All clips")
|
||||||
|
print()
|
||||||
|
while True:
|
||||||
|
choice = input("Which clips? (e.g. 1,3 or a for all): ").strip().lower()
|
||||||
|
if choice in ('a', 'all'):
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
indices = [int(x.strip()) for x in choice.split(",")]
|
||||||
|
if all(1 <= x <= len(clips) for x in indices):
|
||||||
|
clips = [clips[x - 1] for x in indices]
|
||||||
|
break
|
||||||
|
print(f" Invalid selection. Enter 1-{len(clips)}, comma-separated, or 'a' for all.")
|
||||||
|
except (ValueError, EOFError):
|
||||||
|
print(f" Enter clip numbers (e.g. 1,3) or 'a' for all")
|
||||||
|
|
||||||
|
# Pick platforms
|
||||||
|
if args.platforms:
|
||||||
|
requested = []
|
||||||
|
for p in args.platforms.split(","):
|
||||||
|
p = p.strip().lower()
|
||||||
|
if p not in PLATFORM_ALIASES:
|
||||||
|
print(f"Unknown platform: {p}")
|
||||||
|
print(f"Valid: {', '.join(valid_names)}")
|
||||||
|
sys.exit(1)
|
||||||
|
requested.append(PLATFORM_ALIASES[p])
|
||||||
|
target_platforms = list(dict.fromkeys(requested))
|
||||||
|
elif not args.yes:
|
||||||
|
print(f"\nPlatforms:\n")
|
||||||
|
for i, p in enumerate(ALL_PLATFORMS):
|
||||||
|
print(f" {i+1}. {PLATFORM_DISPLAY[p]}")
|
||||||
|
print(f"\n a. All platforms (default)")
|
||||||
|
print()
|
||||||
|
choice = input("Which platforms? (e.g. 1,3,5 or a for all) [a]: ").strip().lower()
|
||||||
|
if choice and choice not in ('a', 'all'):
|
||||||
|
try:
|
||||||
|
indices = [int(x.strip()) for x in choice.split(",")]
|
||||||
|
target_platforms = [ALL_PLATFORMS[x - 1] for x in indices if 1 <= x <= len(ALL_PLATFORMS)]
|
||||||
|
if not target_platforms:
|
||||||
|
target_platforms = ALL_PLATFORMS[:]
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
target_platforms = ALL_PLATFORMS[:]
|
||||||
|
else:
|
||||||
|
target_platforms = ALL_PLATFORMS[:]
|
||||||
|
else:
|
||||||
|
target_platforms = ALL_PLATFORMS[:]
|
||||||
|
|
||||||
|
DIRECT_PLATFORMS = {"bluesky", "youtube"}
|
||||||
|
needs_postiz = not args.dry_run and any(
|
||||||
|
p not in DIRECT_PLATFORMS for p in target_platforms)
|
||||||
|
if needs_postiz:
|
||||||
|
print("Fetching connected accounts from Postiz...")
|
||||||
|
integrations = fetch_integrations()
|
||||||
|
else:
|
||||||
|
integrations = []
|
||||||
|
|
||||||
|
active_platforms = {}
|
||||||
|
for platform in target_platforms:
|
||||||
|
if platform == "bluesky":
|
||||||
|
if BSKY_APP_PASSWORD or args.dry_run:
|
||||||
|
active_platforms[platform] = {"name": BSKY_HANDLE, "_direct": True}
|
||||||
|
else:
|
||||||
|
print("Warning: BSKY_APP_PASSWORD not set in .env, skipping Bluesky")
|
||||||
|
continue
|
||||||
|
if platform == "youtube":
|
||||||
|
if YT_CLIENT_SECRETS.exists() or YT_TOKEN_FILE.exists() or args.dry_run:
|
||||||
|
active_platforms[platform] = {"name": "YouTube Shorts", "_direct": True}
|
||||||
|
else:
|
||||||
|
print("Warning: youtube_client_secrets.json not found, skipping YouTube")
|
||||||
|
continue
|
||||||
|
if args.dry_run:
|
||||||
|
active_platforms[platform] = {"name": PLATFORM_DISPLAY[platform]}
|
||||||
|
continue
|
||||||
|
integ = find_integration(integrations, platform)
|
||||||
|
if integ:
|
||||||
|
active_platforms[platform] = integ
|
||||||
|
else:
|
||||||
|
print(f"Warning: No {PLATFORM_DISPLAY[platform]} account connected in Postiz")
|
||||||
|
|
||||||
|
if not args.dry_run and not active_platforms:
|
||||||
|
print("Error: No platforms available to upload to")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
platform_names = [f"{PLATFORM_DISPLAY[p]} ({integ.get('name', 'connected')})"
|
||||||
|
for p, integ in active_platforms.items()]
|
||||||
|
|
||||||
|
print(f"\nUploading {len(clips)} clip(s) to: {', '.join(platform_names)}")
|
||||||
|
if args.schedule:
|
||||||
|
print(f"Scheduled for: {args.schedule}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
for i, clip in enumerate(clips):
|
||||||
|
print(f" {i+1}. \"{clip['title']}\" ({clip['duration']:.0f}s)")
|
||||||
|
desc = clip.get('description', '')
|
||||||
|
if len(desc) > 80:
|
||||||
|
desc = desc[:desc.rfind(' ', 0, 80)] + '...'
|
||||||
|
print(f" {desc}")
|
||||||
|
print(f" {' '.join(clip.get('hashtags', []))}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
if args.dry_run:
|
||||||
|
print("Dry run — nothing uploaded.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not args.yes:
|
||||||
|
confirm = input("Proceed? [y/N] ").strip().lower()
|
||||||
|
if confirm != "y":
|
||||||
|
print("Cancelled.")
|
||||||
|
return
|
||||||
|
|
||||||
|
upload_history = load_upload_history(clips_dir)
|
||||||
|
|
||||||
|
for i, clip in enumerate(clips):
|
||||||
|
clip_file = clips_dir / clip["clip_file"]
|
||||||
|
if not clip_file.exists():
|
||||||
|
print(f" Clip {i+1}: Video file not found: {clip_file}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
clip_key = clip["clip_file"]
|
||||||
|
already_uploaded = set(upload_history.get(clip_key, []))
|
||||||
|
remaining_platforms = {p: integ for p, integ in active_platforms.items()
|
||||||
|
if p not in already_uploaded}
|
||||||
|
|
||||||
|
if not remaining_platforms:
|
||||||
|
print(f"\n Clip {i+1}: \"{clip['title']}\" — already uploaded to all selected platforms, skipping")
|
||||||
|
continue
|
||||||
|
|
||||||
|
skipped = already_uploaded & set(active_platforms.keys())
|
||||||
|
if skipped:
|
||||||
|
print(f"\n Clip {i+1}: \"{clip['title']}\" (skipping already uploaded: {', '.join(sorted(skipped))})")
|
||||||
|
else:
|
||||||
|
print(f"\n Clip {i+1}: \"{clip['title']}\"")
|
||||||
|
|
||||||
|
postiz_platforms = {p: integ for p, integ in remaining_platforms.items()
|
||||||
|
if not integ.get("_direct")}
|
||||||
|
|
||||||
|
media = None
|
||||||
|
if postiz_platforms:
|
||||||
|
print(f" Uploading {clip_file.name}...")
|
||||||
|
media = upload_file(clip_file)
|
||||||
|
if not media:
|
||||||
|
print(" Failed to upload video to Postiz, skipping Postiz platforms")
|
||||||
|
postiz_platforms = {}
|
||||||
|
else:
|
||||||
|
print(f" Uploaded: {media.get('path', 'ok')}")
|
||||||
|
|
||||||
|
for platform, integ in postiz_platforms.items():
|
||||||
|
display = PLATFORM_DISPLAY[platform]
|
||||||
|
print(f" Posting to {display}...")
|
||||||
|
content = build_content(clip, platform)
|
||||||
|
settings = build_settings(clip, platform)
|
||||||
|
result = create_post(integ["id"], content, media, settings, args.schedule)
|
||||||
|
if result:
|
||||||
|
print(f" {display}: Posted!")
|
||||||
|
upload_history.setdefault(clip_key, []).append(platform)
|
||||||
|
save_upload_history(clips_dir, upload_history)
|
||||||
|
else:
|
||||||
|
print(f" {display}: Failed")
|
||||||
|
|
||||||
|
if "youtube" in remaining_platforms:
|
||||||
|
print(f" Posting to YouTube Shorts (direct)...")
|
||||||
|
try:
|
||||||
|
yt_video_id = post_to_youtube(clip, clip_file)
|
||||||
|
if yt_video_id:
|
||||||
|
print(f" YouTube: Posted!")
|
||||||
|
upload_history.setdefault(clip_key, []).append("youtube")
|
||||||
|
save_upload_history(clips_dir, upload_history)
|
||||||
|
else:
|
||||||
|
print(f" YouTube: Failed")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" YouTube: Failed — {e}")
|
||||||
|
|
||||||
|
if "bluesky" in remaining_platforms:
|
||||||
|
print(f" Posting to Bluesky (direct)...")
|
||||||
|
try:
|
||||||
|
if post_to_bluesky(clip, clip_file):
|
||||||
|
print(f" Bluesky: Posted!")
|
||||||
|
upload_history.setdefault(clip_key, []).append("bluesky")
|
||||||
|
save_upload_history(clips_dir, upload_history)
|
||||||
|
else:
|
||||||
|
print(f" Bluesky: Failed")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" Bluesky: Failed — {e}")
|
||||||
|
|
||||||
|
# Sync clips to website if any YouTube uploads happened
|
||||||
|
if "youtube" in active_platforms:
|
||||||
|
sync_clips_to_website()
|
||||||
|
|
||||||
|
print("\nDone!")
|
||||||
|
|
||||||
|
|
||||||
|
WEBSITE_DIR = Path(__file__).parent / "website"
|
||||||
|
CLIPS_JSON = WEBSITE_DIR / "data" / "clips.json"
|
||||||
|
THUMBS_DIR = WEBSITE_DIR / "images" / "clips"
|
||||||
|
CLIPS_ROOT = Path(__file__).parent / "clips"
|
||||||
|
|
||||||
|
|
||||||
|
def sync_clips_to_website():
|
||||||
|
"""Rebuild website/data/clips.json from YouTube shorts and deploy."""
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
print("\nSyncing clips to website...")
|
||||||
|
|
||||||
|
# Fetch all YouTube shorts from channel
|
||||||
|
result = subprocess.run(
|
||||||
|
["python3", "-m", "yt_dlp", "--flat-playlist", "--print", "%(id)s\t%(title)s",
|
||||||
|
"https://www.youtube.com/lukemacneil/shorts"],
|
||||||
|
capture_output=True, text=True, timeout=60,
|
||||||
|
)
|
||||||
|
if not result.stdout.strip():
|
||||||
|
print(" Could not fetch YouTube shorts, skipping sync")
|
||||||
|
return
|
||||||
|
|
||||||
|
yt_shorts = {}
|
||||||
|
for line in result.stdout.strip().split("\n"):
|
||||||
|
if "\t" not in line:
|
||||||
|
continue
|
||||||
|
vid_id, title = line.split("\t", 1)
|
||||||
|
clean_title = re.sub(r"\s*#Shorts\s*$", "", title).strip().lower()
|
||||||
|
yt_shorts[clean_title] = vid_id
|
||||||
|
|
||||||
|
print(f" Found {len(yt_shorts)} YouTube shorts")
|
||||||
|
|
||||||
|
# Load all clip metadata and match to YouTube
|
||||||
|
existing = {}
|
||||||
|
if CLIPS_JSON.exists():
|
||||||
|
for c in json.loads(CLIPS_JSON.read_text()):
|
||||||
|
existing[c["clip_file"]] = c
|
||||||
|
|
||||||
|
new_clips = []
|
||||||
|
for ep_dir in sorted(CLIPS_ROOT.glob("episode-*")):
|
||||||
|
meta_file = ep_dir / "clips-metadata.json"
|
||||||
|
if not meta_file.exists():
|
||||||
|
continue
|
||||||
|
for clip in json.loads(meta_file.read_text()):
|
||||||
|
clip_title = clip["title"].strip().lower()
|
||||||
|
yt_id = yt_shorts.get(clip_title, "")
|
||||||
|
if not yt_id:
|
||||||
|
for yt_title, yid in yt_shorts.items():
|
||||||
|
if yt_title in clip_title or clip_title in yt_title:
|
||||||
|
yt_id = yid
|
||||||
|
break
|
||||||
|
if not yt_id:
|
||||||
|
continue
|
||||||
|
|
||||||
|
prev = existing.get(clip["clip_file"], {})
|
||||||
|
new_clips.append({
|
||||||
|
"title": clip["title"],
|
||||||
|
"description": clip.get("description", clip.get("caption_text", "")),
|
||||||
|
"episode_number": clip.get("episode_number", 0),
|
||||||
|
"clip_file": clip["clip_file"],
|
||||||
|
"youtube_id": yt_id,
|
||||||
|
"featured": prev.get("featured", False),
|
||||||
|
"thumbnail": prev.get("thumbnail", ""),
|
||||||
|
})
|
||||||
|
|
||||||
|
new_clips.sort(key=lambda c: c["episode_number"], reverse=True)
|
||||||
|
|
||||||
|
# Generate thumbnails for clips that don't have one
|
||||||
|
THUMBS_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
for clip in new_clips:
|
||||||
|
if clip["thumbnail"]:
|
||||||
|
thumb_path = WEBSITE_DIR / clip["thumbnail"]
|
||||||
|
if thumb_path.exists():
|
||||||
|
continue
|
||||||
|
|
||||||
|
thumb_name = clip["clip_file"].replace(".mp4", ".jpg")
|
||||||
|
thumb_path = THUMBS_DIR / thumb_name
|
||||||
|
ep_num = clip["episode_number"]
|
||||||
|
mp4_path = CLIPS_ROOT / f"episode-{ep_num}" / clip["clip_file"]
|
||||||
|
|
||||||
|
if not mp4_path.exists():
|
||||||
|
continue
|
||||||
|
|
||||||
|
subprocess.run(
|
||||||
|
["ffmpeg", "-y", "-i", str(mp4_path), "-ss", "3", "-vframes", "1",
|
||||||
|
"-update", "1", "-vf", "scale=360:-2", "-q:v", "4", str(thumb_path)],
|
||||||
|
capture_output=True, timeout=30,
|
||||||
|
)
|
||||||
|
if thumb_path.exists():
|
||||||
|
clip["thumbnail"] = f"images/clips/{thumb_name}"
|
||||||
|
print(f" Generated thumbnail: {thumb_name}")
|
||||||
|
|
||||||
|
# Ensure at least 3 featured
|
||||||
|
featured_count = sum(1 for c in new_clips if c.get("featured"))
|
||||||
|
if featured_count < 3:
|
||||||
|
for c in new_clips:
|
||||||
|
if not c.get("featured"):
|
||||||
|
c["featured"] = True
|
||||||
|
featured_count += 1
|
||||||
|
if featured_count >= 3:
|
||||||
|
break
|
||||||
|
|
||||||
|
CLIPS_JSON.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
CLIPS_JSON.write_text(json.dumps(new_clips, indent=2))
|
||||||
|
print(f" Updated clips.json: {len(new_clips)} clips")
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
print(" Deploying website...")
|
||||||
|
deploy = subprocess.run(
|
||||||
|
["npx", "wrangler", "pages", "deploy", "website/",
|
||||||
|
"--project-name=lukeattheroost", "--branch=main", "--commit-dirty=true"],
|
||||||
|
capture_output=True, text=True, timeout=120,
|
||||||
|
cwd=str(Path(__file__).parent),
|
||||||
|
)
|
||||||
|
if "Deployment complete" in deploy.stdout:
|
||||||
|
print(" Website deployed!")
|
||||||
|
else:
|
||||||
|
print(f" Deploy failed: {deploy.stderr[-300:]}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Page Not Found — Luke at the Roost</title>
|
||||||
|
<meta name="description" content="The page you're looking for doesn't exist.">
|
||||||
|
<meta name="theme-color" content="#1a1209">
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.ico" sizes="48x48">
|
||||||
|
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||||
|
<link rel="icon" type="image/png" sizes="192x192" href="favicon-192.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="48x48" href="favicon-48.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
||||||
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<a href="#main-content" class="skip-link">Skip to content</a>
|
||||||
|
|
||||||
|
<nav class="site-nav">
|
||||||
|
<a href="/" class="site-nav-brand">Luke at the Roost</a>
|
||||||
|
<div class="site-nav-links">
|
||||||
|
<a href="/how-it-works">How It Works</a>
|
||||||
|
<a href="/clips">Clips</a>
|
||||||
|
<a href="/stats">Stats</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main id="main-content">
|
||||||
|
|
||||||
|
<section class="page-header">
|
||||||
|
<h1>404 — Page Not Found</h1>
|
||||||
|
<p class="page-subtitle">Looks like this page wandered off into the desert.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="about-section">
|
||||||
|
<p>The page you're looking for doesn't exist or may have been moved.</p>
|
||||||
|
<p><a href="/">Back to the show</a> · <a href="/clips">Watch clips</a> · <a href="/how-it-works">How it works</a></p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer"></footer>
|
||||||
|
<script src="js/footer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/episodes.html /episode 302
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
const VOICEMAIL_XML = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Response>
|
||||||
|
<Say voice="woman">Luke at the Roost is off the air right now. Leave a message after the beep and we may play it on the next show!</Say>
|
||||||
|
<Record maxLength="120" action="https://radioshow.macneilmediagroup.com/api/signalwire/voicemail-complete" playBeep="true" />
|
||||||
|
<Say voice="woman">Thank you for calling. Goodbye!</Say>
|
||||||
|
<Hangup/>
|
||||||
|
</Response>`;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
async fetch(request, env) {
|
||||||
|
const url = new URL(request.url);
|
||||||
|
|
||||||
|
if (url.pathname === "/api/signalwire/voice") {
|
||||||
|
try {
|
||||||
|
const body = await request.text();
|
||||||
|
const resp = await fetch("https://radioshow.macneilmediagroup.com/api/signalwire/voice", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||||
|
body: body,
|
||||||
|
signal: AbortSignal.timeout(5000),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (resp.ok) {
|
||||||
|
return new Response(await resp.text(), {
|
||||||
|
status: 200,
|
||||||
|
headers: { "Content-Type": "application/xml" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Server unreachable or timed out
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response(VOICEMAIL_XML, {
|
||||||
|
status: 200,
|
||||||
|
headers: { "Content-Type": "application/xml" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSS feed proxy
|
||||||
|
if (url.pathname === "/feed") {
|
||||||
|
try {
|
||||||
|
const resp = await fetch("https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml", {
|
||||||
|
signal: AbortSignal.timeout(8000),
|
||||||
|
});
|
||||||
|
if (resp.ok) {
|
||||||
|
return new Response(await resp.text(), {
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml",
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
"Cache-Control": "public, max-age=300",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Castopod unreachable
|
||||||
|
}
|
||||||
|
return new Response("Feed unavailable", { status: 502 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plausible analytics proxy (bypass ad blockers)
|
||||||
|
if (url.pathname === "/p/script") {
|
||||||
|
const resp = await fetch("https://plausible.macneilmediagroup.com/js/script.file-downloads.hash.outbound-links.pageview-props.revenue.tagged-events.js");
|
||||||
|
return new Response(await resp.text(), {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/javascript",
|
||||||
|
"Cache-Control": "public, max-age=86400",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.pathname === "/p/event" && request.method === "POST") {
|
||||||
|
const body = await request.text();
|
||||||
|
const resp = await fetch("https://plausible.macneilmediagroup.com/api/event", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"User-Agent": request.headers.get("User-Agent") || "",
|
||||||
|
"X-Forwarded-For": request.headers.get("CF-Connecting-IP") || request.headers.get("X-Forwarded-For") || "",
|
||||||
|
},
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
return new Response(resp.body, {
|
||||||
|
status: resp.status,
|
||||||
|
headers: { "Content-Type": resp.headers.get("Content-Type") || "text/plain" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Social crawler meta injection for episode pages
|
||||||
|
if (url.pathname === "/episode.html" && url.searchParams.get("slug")) {
|
||||||
|
const ua = (request.headers.get("User-Agent") || "").toLowerCase();
|
||||||
|
const isCrawler = /facebookexternalhit|twitterbot|linkedinbot|slackbot|discordbot|telegrambot|whatsapp|pinterest|redditbot/i.test(ua);
|
||||||
|
|
||||||
|
if (isCrawler) {
|
||||||
|
const slug = url.searchParams.get("slug");
|
||||||
|
try {
|
||||||
|
const feedResp = await fetch("https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml", {
|
||||||
|
signal: AbortSignal.timeout(5000),
|
||||||
|
});
|
||||||
|
if (feedResp.ok) {
|
||||||
|
const feedXml = await feedResp.text();
|
||||||
|
const items = feedXml.split("<item>");
|
||||||
|
let title = "";
|
||||||
|
let description = "";
|
||||||
|
|
||||||
|
for (let i = 1; i < items.length; i++) {
|
||||||
|
const item = items[i];
|
||||||
|
const linkMatch = item.match(/<link>(.*?)<\/link>/);
|
||||||
|
if (linkMatch) {
|
||||||
|
const itemSlug = linkMatch[1].split("/episodes/").pop()?.replace(/\/$/, "");
|
||||||
|
if (itemSlug === slug) {
|
||||||
|
const titleMatch = item.match(/<title>(.*?)<\/title>/);
|
||||||
|
title = titleMatch ? titleMatch[1].replace(/<!\[CDATA\[|\]\]>/g, "").trim() : "";
|
||||||
|
const descMatch = item.match(/<description>([\s\S]*?)<\/description>/);
|
||||||
|
description = descMatch
|
||||||
|
? descMatch[1].replace(/<!\[CDATA\[|\]\]>/g, "").replace(/<[^>]+>/g, "").trim().slice(0, 200)
|
||||||
|
: "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (title) {
|
||||||
|
const pageResp = await env.ASSETS.fetch(request);
|
||||||
|
let html = await pageResp.text();
|
||||||
|
|
||||||
|
const escTitle = title.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
||||||
|
const escDesc = description.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
||||||
|
const canonicalUrl = `https://lukeattheroost.com/episode.html?slug=${slug}`;
|
||||||
|
|
||||||
|
html = html.replace(/<meta property="og:title"[^>]*>/, `<meta property="og:title" content="${escTitle}">`);
|
||||||
|
html = html.replace(/<meta property="og:description"[^>]*>/, `<meta property="og:description" content="${escDesc}">`);
|
||||||
|
html = html.replace(/<meta property="og:url"[^>]*>/, `<meta property="og:url" content="${canonicalUrl}">`);
|
||||||
|
html = html.replace(/<meta name="twitter:title"[^>]*>/, `<meta name="twitter:title" content="${escTitle}">`);
|
||||||
|
html = html.replace(/<meta name="twitter:description"[^>]*>/, `<meta name="twitter:description" content="${escDesc}">`);
|
||||||
|
html = html.replace(/<title[^>]*>.*?<\/title>/, `<title>${escTitle} — Luke at the Roost</title>`);
|
||||||
|
|
||||||
|
return new Response(html, {
|
||||||
|
status: 200,
|
||||||
|
headers: { "Content-Type": "text/html;charset=UTF-8" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Fall through to static page
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other requests — serve static assets
|
||||||
|
return env.ASSETS.fetch(request);
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Clips — Luke at the Roost</title>
|
||||||
|
<meta name="description" content="The best moments from Luke at the Roost — watch clips from the AI call-in comedy podcast.">
|
||||||
|
<meta name="theme-color" content="#1a1209">
|
||||||
|
<link rel="canonical" href="https://lukeattheroost.com/clips">
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="Luke at the Roost">
|
||||||
|
<meta property="og:title" content="Clips — Luke at the Roost">
|
||||||
|
<meta property="og:description" content="The best moments from Luke at the Roost — watch clips from the AI call-in comedy podcast.">
|
||||||
|
<meta property="og:image" content="https://cdn.lukeattheroost.com/media/podcasts/LukeAtTheRoost/cover_feed.png?v=3">
|
||||||
|
<meta property="og:url" content="https://lukeattheroost.com/clips">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title" content="Clips — Luke at the Roost">
|
||||||
|
<meta name="twitter:description" content="The best moments from Luke at the Roost — watch clips from the AI call-in comedy podcast.">
|
||||||
|
<meta name="twitter:image" content="https://cdn.lukeattheroost.com/media/podcasts/LukeAtTheRoost/cover_feed.png?v=3">
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.ico" sizes="48x48">
|
||||||
|
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||||
|
<link rel="icon" type="image/png" sizes="192x192" href="favicon-192.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="48x48" href="favicon-48.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
||||||
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "BreadcrumbList",
|
||||||
|
"itemListElement": [
|
||||||
|
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://lukeattheroost.com" },
|
||||||
|
{ "@type": "ListItem", "position": 2, "name": "Clips" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
||||||
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<a href="#main-content" class="skip-link">Skip to content</a>
|
||||||
|
|
||||||
|
<nav class="site-nav">
|
||||||
|
<a href="/" class="site-nav-brand">Luke at the Roost</a>
|
||||||
|
<div class="site-nav-links">
|
||||||
|
<a href="/how-it-works">How It Works</a>
|
||||||
|
<a href="/clips" aria-current="page">Clips</a>
|
||||||
|
<a href="/stats">Stats</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main id="main-content">
|
||||||
|
|
||||||
|
<section class="page-header">
|
||||||
|
<h1>Clips</h1>
|
||||||
|
<p class="page-subtitle">The best moments from the show</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="clips-section-header">
|
||||||
|
<h2>Featured</h2>
|
||||||
|
</div>
|
||||||
|
<section class="clips-featured"></section>
|
||||||
|
|
||||||
|
<div class="clips-section-header">
|
||||||
|
<h2>All Clips</h2>
|
||||||
|
</div>
|
||||||
|
<section class="clips-grid"></section>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer"></footer>
|
||||||
|
|
||||||
|
<script src="js/footer.js"></script>
|
||||||
|
<script src="js/clips.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"title": "Cult Leader Realizes He's Been Manipulating People",
|
||||||
|
"description": "Cult leader calls in having a full existential crisis about his 'shared intimacy nights' and the manipulation tactics he's been using on his followers.",
|
||||||
|
"episode_number": 37,
|
||||||
|
"clip_file": "clip-3-cult-leader-realizes-he-s-been-manipulating-people.mp4",
|
||||||
|
"youtube_id": "zmCfOQuXtBE",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-3-cult-leader-realizes-he-s-been-manipulating-people.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Intern Pitches Himself Live On Air",
|
||||||
|
"description": "This intern used his first day on the job to shoot his shot with the entire radio audience. The therapy line is sending me.",
|
||||||
|
"episode_number": 36,
|
||||||
|
"clip_file": "clip-1-intern-pitches-himself-live-on-air.mp4",
|
||||||
|
"youtube_id": "exO3_9ewKH0",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-1-intern-pitches-himself-live-on-air.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Wait Until She Dies or Kill Her",
|
||||||
|
"description": "Luke gives the most UNHINGED inheritance advice I've ever heard on live radio. This escalated so fast.",
|
||||||
|
"episode_number": 35,
|
||||||
|
"clip_file": "clip-1-wait-until-she-dies-or-kill-her.mp4",
|
||||||
|
"youtube_id": "03oJoRh-ioo",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-1-wait-until-she-dies-or-kill-her.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Nobody's Potato Salad Is Good",
|
||||||
|
"description": "Luke goes OFF on workplace potlucks: 'Nobody's potato salad is f***ing good, alright? Everything at a potluck is gross. Just take everybody to McDonald's.'",
|
||||||
|
"episode_number": 34,
|
||||||
|
"clip_file": "clip-3-nobody-s-potato-salad-is-good.mp4",
|
||||||
|
"youtube_id": "re7C2woMUrA",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-3-nobody-s-potato-salad-is-good.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Man Obsessed With Dead Nun Loses Wife",
|
||||||
|
"description": "Rodney couldn't stop talking about a dead nun who shared his wife's name. His wife was NOT amused.",
|
||||||
|
"episode_number": 33,
|
||||||
|
"clip_file": "clip-1-man-obsessed-with-dead-nun-loses-wife.mp4",
|
||||||
|
"youtube_id": "zD8CdX7s8us",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-1-man-obsessed-with-dead-nun-loses-wife.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "I Faked Cancer to Skip a Wedding",
|
||||||
|
"description": "A small lie to skip his sister's FOURTH wedding spiraled into a GoFundMe, a pancake breakfast fundraiser, and a $4,700 check. Now he's in too deep.",
|
||||||
|
"episode_number": 32,
|
||||||
|
"clip_file": "clip-1-i-faked-cancer-to-skip-a-wedding.mp4",
|
||||||
|
"youtube_id": "NUkhsPfMx9o",
|
||||||
|
"featured": true,
|
||||||
|
"thumbnail": "images/clips/clip-1-i-faked-cancer-to-skip-a-wedding.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Started a Fight and Can't Stop Reading About Wars",
|
||||||
|
"description": "A caller starts a fight with their partner and spirals into an obsessive deep-dive on historical wars. Luke tries to untangle the connection.",
|
||||||
|
"episode_number": 31,
|
||||||
|
"clip_file": "clip-3-started-a-fight-and-can-t-stop-reading-about-wars.mp4",
|
||||||
|
"youtube_id": "D2iWnSGQeow",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-3-started-a-fight-and-can-t-stop-reading-about-wars.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Latex Fetish Confession Goes Silent",
|
||||||
|
"description": "He finally opened up about his latex fetish to his girlfriend and got 10 seconds of pure silence. Now he's wondering if honesty just cost him everything.",
|
||||||
|
"episode_number": 30,
|
||||||
|
"clip_file": "clip-3-latex-fetish-confession-goes-silent.mp4",
|
||||||
|
"youtube_id": "vFvWUbYacug",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-3-latex-fetish-confession-goes-silent.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Adopted Daughter Might Have Been Stolen",
|
||||||
|
"description": "A lawyer in Guatemala just sent him proof that his adopted daughter might have been stolen from her birth mother. The photo shows the same crooked smile and now everything is falling apart.",
|
||||||
|
"episode_number": 29,
|
||||||
|
"clip_file": "clip-3-adopted-daughter-might-have-been-stolen.mp4",
|
||||||
|
"youtube_id": "hMxldZN3VHw",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-3-adopted-daughter-might-have-been-stolen.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Vinyl vs Digital: The Warmth Debate",
|
||||||
|
"description": "Vinyl collector calls in to absolutely torch the 'warmth' argument. Turns out what you love about records might just be... imperfection.",
|
||||||
|
"episode_number": 28,
|
||||||
|
"clip_file": "clip-2-vinyl-vs-digital-the-warmth-debate.mp4",
|
||||||
|
"youtube_id": "aVmhApa0d2E",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-2-vinyl-vs-digital-the-warmth-debate.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Open Marriage Backfired Spectacularly",
|
||||||
|
"description": "She thought opening up the marriage would spice things up. He's living his best life while she can't even get a text back.",
|
||||||
|
"episode_number": 27,
|
||||||
|
"clip_file": "clip-2-open-marriage-backfired-spectacularly.mp4",
|
||||||
|
"youtube_id": "-K-t7iijfGs",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-2-open-marriage-backfired-spectacularly.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Neighbor's Roomba Breaks Into Kitchen at 2:30 AM",
|
||||||
|
"description": "She woke up at 2:30 AM to find her neighbor Gary's Roomba cleaning her kitchen. Yes, it had Gary's name on it. Yes, it came through the dog door.",
|
||||||
|
"episode_number": 26,
|
||||||
|
"clip_file": "clip-2-neighbor-s-roomba-breaks-into-kitchen-at-2-30-am.mp4",
|
||||||
|
"youtube_id": "J7bfT6jsykA",
|
||||||
|
"featured": true,
|
||||||
|
"thumbnail": "images/clips/clip-2-neighbor-s-roomba-breaks-into-kitchen-at-2-30-am.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "You're a Computer-Generated AI Caller",
|
||||||
|
"description": "The AI caller admits it: 'You're right. I am computer-generated. And you're sitting there alone at midnight talking to me like it's real.' Luke's reaction is everything.",
|
||||||
|
"episode_number": 24,
|
||||||
|
"clip_file": "clip-10-you-re-a-computer-generated-ai-caller.mp4",
|
||||||
|
"youtube_id": "QVcoU59OTRA",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-10-you-re-a-computer-generated-ai-caller.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Full Banana Costume at Work Party",
|
||||||
|
"description": "He showed up to his manager's holiday party in a full banana costume and now HR says it shows 'lack of professional judgment.' Was it really that serious?",
|
||||||
|
"episode_number": 23,
|
||||||
|
"clip_file": "clip-4-full-banana-costume-at-work-party.mp4",
|
||||||
|
"youtube_id": "enyqXHxmzqA",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-4-full-banana-costume-at-work-party.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "The Poison That Saved Everything",
|
||||||
|
"description": "The apocalypse that saved us all. 2.5 billion years ago, oxygen poisoned nearly everything on Earth\u2014and that catastrophe made life as we know it possible.",
|
||||||
|
"episode_number": 22,
|
||||||
|
"clip_file": "clip-1-the-poison-that-saved-everything.mp4",
|
||||||
|
"youtube_id": "BHm3RJ5YC_8",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-1-the-poison-that-saved-everything.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "I Burned My Marriage for Work",
|
||||||
|
"description": "He burned his second marriage to the ground chasing work. His wife didn't leave because of money\u2014she left because he was never there.",
|
||||||
|
"episode_number": 22,
|
||||||
|
"clip_file": "clip-3-i-burned-my-marriage-for-work.mp4",
|
||||||
|
"youtube_id": "1a_9Yl-isN0",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-3-i-burned-my-marriage-for-work.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Shopping Cart Theory: Moral Test or Crazy?",
|
||||||
|
"description": "A caller defends the shopping cart theory by admitting they literally watch people from their workplace. Luke has some thoughts on what's actually crazy here.",
|
||||||
|
"episode_number": 21,
|
||||||
|
"clip_file": "clip-2-shopping-cart-theory-moral-test-or-crazy.mp4",
|
||||||
|
"youtube_id": "KijyJsMZfkA",
|
||||||
|
"featured": true,
|
||||||
|
"thumbnail": "images/clips/clip-2-shopping-cart-theory-moral-test-or-crazy.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Dog Takes a Shit With Leg Up",
|
||||||
|
"description": "This caller's dog just unlocked a new achievement that has him bursting with pride. You won't believe what had him celebrating like his pup won best in show.",
|
||||||
|
"episode_number": 20,
|
||||||
|
"clip_file": "clip-1-dog-takes-a-shit-with-leg-up.mp4",
|
||||||
|
"youtube_id": "SXcCrlQTuwM",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-1-dog-takes-a-shit-with-leg-up.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Don't Get Married PSA",
|
||||||
|
"description": "A brutal take on marriage from someone who learned the hard way. This caller is not holding back with the relationship advice tonight.",
|
||||||
|
"episode_number": 19,
|
||||||
|
"clip_file": "clip-2-don-t-get-married-psa.mp4",
|
||||||
|
"youtube_id": "6pKcYXgzizs",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-2-don-t-get-married-psa.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Signed Into an Illegal Poker Game",
|
||||||
|
"description": "Imagine walking into an illegal poker game and they make you sign a guest book with your real info. The audacity is actually impressive.",
|
||||||
|
"episode_number": 18,
|
||||||
|
"clip_file": "clip-2-signed-into-an-illegal-poker-game.mp4",
|
||||||
|
"youtube_id": "eCT0gUVLlbA",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-2-signed-into-an-illegal-poker-game.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "We're Dinner for a Black Hole",
|
||||||
|
"description": "This caller has a theory that we're all just corn on the cob waiting to be eaten by a distant black hole. Can't stop thinking about it now.",
|
||||||
|
"episode_number": 17,
|
||||||
|
"clip_file": "clip-2-we-re-dinner-for-a-black-hole.mp4",
|
||||||
|
"youtube_id": "lakicW3cbPw",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-2-we-re-dinner-for-a-black-hole.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Maybe You Should Eat More of Her",
|
||||||
|
"description": "Luke doesn't hold back when a caller complains about his long-distance girlfriend not visiting enough. This relationship advice is absolutely WILD and you need to hear it.",
|
||||||
|
"episode_number": 16,
|
||||||
|
"clip_file": "clip-1-maybe-you-should-eat-more-of-her.mp4",
|
||||||
|
"youtube_id": "P5UNb_njsig",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-1-maybe-you-should-eat-more-of-her.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "I Lied About Speaking Spanish for 8 Years",
|
||||||
|
"description": "This crop duster faked speaking Spanish to get hired and somehow kept the lie going for EIGHT YEARS. Now he's got a 3-week contract in Mexico City and he's about to get exposed.",
|
||||||
|
"episode_number": 14,
|
||||||
|
"clip_file": "clip-1-i-lied-about-speaking-spanish-for-8-years.mp4",
|
||||||
|
"youtube_id": "MxDjohJEneQ",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-1-i-lied-about-speaking-spanish-for-8-years.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "You Can't Have It Both Ways",
|
||||||
|
"description": "This caller goes OFF on absent parents who use work as an excuse. Just because you're making money on the road doesn't mean you're present in your kid's life.",
|
||||||
|
"episode_number": 13,
|
||||||
|
"clip_file": "clip-2-you-can-t-have-it-both-ways.mp4",
|
||||||
|
"youtube_id": "Or62RF0uJQM",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-2-you-can-t-have-it-both-ways.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Pretending to Buy Houses for 8 Months",
|
||||||
|
"description": "For 8 months, this caller has been attending open houses every weekend pretending to be different people. They're not buying... they're just living fake lives for fun.",
|
||||||
|
"episode_number": 13,
|
||||||
|
"clip_file": "clip-3-pretending-to-buy-houses-for-8-months.mp4",
|
||||||
|
"youtube_id": "VSWknaHx7d0",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-3-pretending-to-buy-houses-for-8-months.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "No More Thursdays in Deming",
|
||||||
|
"description": "Rita thought she was being sneaky meeting her ex every Thursday at a Deming motel... until her husband started tracking the mileage. Luke's response? Absolutely brutal.",
|
||||||
|
"episode_number": 11,
|
||||||
|
"clip_file": "clip-1-no-more-thursdays-in-deming.mp4",
|
||||||
|
"youtube_id": "weeDjSi7vuc",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-1-no-more-thursdays-in-deming.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Cemetery Widow Stalker",
|
||||||
|
"description": "A cemetery groundskeeper thought a widow was mourning her husband... until he realized she keeps showing up at midnight asking his COWORKERS about him. This one gets creepy fast.",
|
||||||
|
"episode_number": 8,
|
||||||
|
"clip_file": "clip-2-cemetery-widow-stalker.mp4",
|
||||||
|
"youtube_id": "dAiM1WT5-_A",
|
||||||
|
"featured": false,
|
||||||
|
"thumbnail": "images/clips/clip-2-cemetery-widow-stalker.jpg"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
||||||
<link rel="stylesheet" href="css/style.css?v=2">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
|
|
||||||
<!-- Structured Data (dynamically updated by JS) -->
|
<!-- Structured Data (dynamically updated by JS) -->
|
||||||
<script type="application/ld+json" id="episode-jsonld">
|
<script type="application/ld+json" id="episode-jsonld">
|
||||||
@@ -48,14 +48,24 @@
|
|||||||
"inLanguage": "en"
|
"inLanguage": "en"
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<!-- Nav -->
|
<a href="#main-content" class="skip-link">Skip to content</a>
|
||||||
<nav class="page-nav">
|
|
||||||
<a href="/" class="nav-home">← Luke at the Roost</a>
|
<nav class="site-nav">
|
||||||
|
<a href="/" class="site-nav-brand">Luke at the Roost</a>
|
||||||
|
<div class="site-nav-links">
|
||||||
|
<a href="/how-it-works">How It Works</a>
|
||||||
|
<a href="/clips">Clips</a>
|
||||||
|
<a href="/stats">Stats</a>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<main id="main-content">
|
||||||
|
|
||||||
<!-- Episode Header -->
|
<!-- Episode Header -->
|
||||||
<section class="ep-header" id="ep-header">
|
<section class="ep-header" id="ep-header">
|
||||||
<div class="ep-header-inner">
|
<div class="ep-header-inner">
|
||||||
@@ -79,38 +89,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
<noscript>
|
<noscript>
|
||||||
<section class="transcript-section">
|
<section class="transcript-section">
|
||||||
<p>This page requires JavaScript to load the episode transcript. Please enable JavaScript or listen on <a href="https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF">Spotify</a>, <a href="https://podcasts.apple.com/us/podcast/luke-at-the-roost/id1875205848">Apple Podcasts</a>, or <a href="https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-">YouTube</a>.</p>
|
<p>This page requires JavaScript to load the episode transcript. Please enable JavaScript or listen on <a href="https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF">Spotify</a>, <a href="https://podcasts.apple.com/us/podcast/luke-at-the-roost/id1875205848">Apple Podcasts</a>, or <a href="https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-">YouTube</a>.</p>
|
||||||
</section>
|
</section>
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|
||||||
<!-- Footer -->
|
<footer class="footer"></footer>
|
||||||
<footer class="footer">
|
|
||||||
<div class="footer-links">
|
|
||||||
<a href="/">Home</a>
|
|
||||||
<a href="/how-it-works">How It Works</a>
|
|
||||||
<a href="/stats">Stats</a>
|
|
||||||
<a href="https://discord.gg/5CnQZxDM" target="_blank" rel="noopener">Discord</a>
|
|
||||||
<a href="https://www.facebook.com/profile.php?id=61588191627949" target="_blank" rel="noopener">Facebook</a>
|
|
||||||
<a href="https://x.com/lukeattheroost" target="_blank" rel="noopener">X</a>
|
|
||||||
<a href="https://bsky.app/profile/lukeattheroost.bsky.social" target="_blank" rel="noopener">Bluesky</a>
|
|
||||||
<a href="https://mastodon.macneilmediagroup.com/@lukeattheroost" target="_blank" rel="me noopener">Mastodon</a>
|
|
||||||
<a href="https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF?si=f990713adce84ba4" target="_blank" rel="noopener">Spotify</a>
|
|
||||||
<a href="https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-" target="_blank" rel="noopener">YouTube</a>
|
|
||||||
<a href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml" target="_blank" rel="noopener">RSS</a>
|
|
||||||
</div>
|
|
||||||
<div class="footer-projects">
|
|
||||||
<span class="footer-projects-label">More from Luke</span>
|
|
||||||
<div class="footer-projects-links">
|
|
||||||
<a href="https://macneilmediagroup.com" target="_blank" rel="noopener">MacNeil Media Group</a>
|
|
||||||
<a href="https://prints.macneilmediagroup.com" target="_blank" rel="noopener">Photography Prints</a>
|
|
||||||
<a href="https://youtube.com/lukemacneil" target="_blank" rel="noopener">YouTube</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="footer-contact">Sales & Collaboration: <a href="mailto:luke@macneilmediagroup.com">luke@macneilmediagroup.com</a></p>
|
|
||||||
<p>© 2026 Luke at the Roost · <a href="/privacy">Privacy Policy</a></p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<!-- Sticky Audio Player -->
|
<!-- Sticky Audio Player -->
|
||||||
<div class="sticky-player" id="sticky-player">
|
<div class="sticky-player" id="sticky-player">
|
||||||
@@ -122,7 +109,7 @@
|
|||||||
<div class="player-info">
|
<div class="player-info">
|
||||||
<div class="player-title" id="player-title">—</div>
|
<div class="player-title" id="player-title">—</div>
|
||||||
<div class="player-progress-row">
|
<div class="player-progress-row">
|
||||||
<div class="player-progress" id="player-progress">
|
<div class="player-progress" id="player-progress" role="slider" aria-label="Audio progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" tabindex="0">
|
||||||
<div class="player-progress-fill" id="player-progress-fill"></div>
|
<div class="player-progress-fill" id="player-progress-fill"></div>
|
||||||
</div>
|
</div>
|
||||||
<span class="player-time" id="player-time">0:00 / 0:00</span>
|
<span class="player-time" id="player-time">0:00 / 0:00</span>
|
||||||
@@ -133,194 +120,8 @@
|
|||||||
|
|
||||||
<audio id="audio-element" preload="none"></audio>
|
<audio id="audio-element" preload="none"></audio>
|
||||||
|
|
||||||
<script>
|
<script src="js/footer.js"></script>
|
||||||
const FEED_URL = '/feed';
|
<script src="js/player.js"></script>
|
||||||
const CDN_BASE = 'https://cdn.lukeattheroost.com';
|
<script src="js/episode.js"></script>
|
||||||
|
|
||||||
const audio = document.getElementById('audio-element');
|
|
||||||
const stickyPlayer = document.getElementById('sticky-player');
|
|
||||||
const playerPlayBtn = document.getElementById('player-play-btn');
|
|
||||||
const playerTitle = document.getElementById('player-title');
|
|
||||||
const playerProgress = document.getElementById('player-progress');
|
|
||||||
const playerProgressFill = document.getElementById('player-progress-fill');
|
|
||||||
const playerTime = document.getElementById('player-time');
|
|
||||||
|
|
||||||
function formatTime(seconds) {
|
|
||||||
if (!seconds || isNaN(seconds)) return '0:00';
|
|
||||||
const s = Math.floor(seconds);
|
|
||||||
const h = Math.floor(s / 3600);
|
|
||||||
const m = Math.floor((s % 3600) / 60);
|
|
||||||
const sec = s % 60;
|
|
||||||
if (h > 0) return `${h}:${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`;
|
|
||||||
return `${m}:${String(sec).padStart(2, '0')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatDate(dateStr) {
|
|
||||||
return new Date(dateStr).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseDuration(raw) {
|
|
||||||
if (!raw) return '';
|
|
||||||
if (raw.includes(':')) {
|
|
||||||
const parts = raw.split(':').map(Number);
|
|
||||||
let t = 0;
|
|
||||||
if (parts.length === 3) t = parts[0]*3600 + parts[1]*60 + parts[2];
|
|
||||||
else if (parts.length === 2) t = parts[0]*60 + parts[1];
|
|
||||||
return `${Math.round(t/60)} min`;
|
|
||||||
}
|
|
||||||
const sec = parseInt(raw, 10);
|
|
||||||
return isNaN(sec) ? '' : `${Math.round(sec/60)} min`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function stripHtml(html) {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.innerHTML = html || '';
|
|
||||||
return div.textContent || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get slug from URL
|
|
||||||
const params = new URLSearchParams(window.location.search);
|
|
||||||
const slug = params.get('slug');
|
|
||||||
|
|
||||||
if (!slug) {
|
|
||||||
document.getElementById('ep-title').textContent = 'Episode not found';
|
|
||||||
document.getElementById('transcript-body').innerHTML = '<p>No episode specified. <a href="/">Go back to episodes.</a></p>';
|
|
||||||
} else {
|
|
||||||
loadEpisode(slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadEpisode(slug) {
|
|
||||||
// Fetch episode info from RSS
|
|
||||||
try {
|
|
||||||
const res = await fetch(FEED_URL);
|
|
||||||
const xml = await res.text();
|
|
||||||
const parser = new DOMParser();
|
|
||||||
const doc = parser.parseFromString(xml, 'text/xml');
|
|
||||||
const items = doc.querySelectorAll('item');
|
|
||||||
|
|
||||||
let episode = null;
|
|
||||||
for (const item of items) {
|
|
||||||
const link = item.querySelector('link')?.textContent || '';
|
|
||||||
const itemSlug = link.split('/episodes/').pop()?.replace(/\/$/, '');
|
|
||||||
if (itemSlug === slug) {
|
|
||||||
episode = {
|
|
||||||
title: item.querySelector('title')?.textContent || 'Untitled',
|
|
||||||
description: item.querySelector('description')?.textContent || '',
|
|
||||||
audioUrl: item.querySelector('enclosure')?.getAttribute('url') || '',
|
|
||||||
pubDate: item.querySelector('pubDate')?.textContent || '',
|
|
||||||
duration: item.getElementsByTagNameNS('http://www.itunes.com/dtds/podcast-1.0.dtd', 'duration')[0]?.textContent || '',
|
|
||||||
episodeNum: item.getElementsByTagNameNS('http://www.itunes.com/dtds/podcast-1.0.dtd', 'episode')[0]?.textContent || '',
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!episode) {
|
|
||||||
document.getElementById('ep-title').textContent = 'Episode not found';
|
|
||||||
document.getElementById('transcript-body').innerHTML = '<p>Could not find this episode. <a href="/">Go back to episodes.</a></p>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate header
|
|
||||||
const metaParts = [
|
|
||||||
episode.episodeNum ? `Episode ${episode.episodeNum}` : '',
|
|
||||||
episode.pubDate ? formatDate(episode.pubDate) : '',
|
|
||||||
parseDuration(episode.duration),
|
|
||||||
].filter(Boolean).join(' \u00b7 ');
|
|
||||||
|
|
||||||
document.getElementById('ep-meta').textContent = metaParts;
|
|
||||||
document.getElementById('ep-title').textContent = episode.title;
|
|
||||||
document.getElementById('ep-desc').innerHTML = episode.description || '';
|
|
||||||
|
|
||||||
// Update page meta
|
|
||||||
document.title = `${episode.title} — Luke at the Roost`;
|
|
||||||
document.getElementById('page-description')?.setAttribute('content', `Full transcript of ${episode.title} from Luke at the Roost.`);
|
|
||||||
document.getElementById('og-title')?.setAttribute('content', episode.title);
|
|
||||||
document.getElementById('og-description')?.setAttribute('content', stripHtml(episode.description).slice(0, 200));
|
|
||||||
const canonicalUrl = `https://lukeattheroost.com/episode.html?slug=${slug}`;
|
|
||||||
document.getElementById('page-canonical')?.setAttribute('href', canonicalUrl);
|
|
||||||
document.getElementById('og-url')?.setAttribute('content', canonicalUrl);
|
|
||||||
document.getElementById('tw-title')?.setAttribute('content', episode.title);
|
|
||||||
document.getElementById('tw-description')?.setAttribute('content', stripHtml(episode.description).slice(0, 200));
|
|
||||||
|
|
||||||
// Update JSON-LD structured data
|
|
||||||
const jsonLd = document.getElementById('episode-jsonld');
|
|
||||||
if (jsonLd) {
|
|
||||||
const ld = JSON.parse(jsonLd.textContent);
|
|
||||||
ld.name = episode.title;
|
|
||||||
ld.url = canonicalUrl;
|
|
||||||
ld.description = stripHtml(episode.description).slice(0, 300);
|
|
||||||
if (episode.pubDate) ld.datePublished = new Date(episode.pubDate).toISOString().split('T')[0];
|
|
||||||
if (episode.episodeNum) ld.episodeNumber = parseInt(episode.episodeNum, 10);
|
|
||||||
if (episode.audioUrl) {
|
|
||||||
ld.associatedMedia = {
|
|
||||||
"@type": "MediaObject",
|
|
||||||
"contentUrl": episode.audioUrl
|
|
||||||
};
|
|
||||||
}
|
|
||||||
jsonLd.textContent = JSON.stringify(ld);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Play button
|
|
||||||
if (episode.audioUrl) {
|
|
||||||
const playBtn = document.getElementById('ep-play-btn');
|
|
||||||
playBtn.style.display = 'inline-flex';
|
|
||||||
playBtn.addEventListener('click', () => {
|
|
||||||
audio.src = episode.audioUrl;
|
|
||||||
audio.play();
|
|
||||||
playerTitle.textContent = episode.title;
|
|
||||||
stickyPlayer.classList.add('active');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
document.getElementById('ep-title').textContent = 'Error loading episode';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch transcript
|
|
||||||
try {
|
|
||||||
const txRes = await fetch(`/transcripts/${slug}.txt`);
|
|
||||||
if (!txRes.ok) throw new Error('Not found');
|
|
||||||
const text = await txRes.text();
|
|
||||||
const paragraphs = text.split(/\n\n+/).filter(Boolean);
|
|
||||||
const html = paragraphs.map(p => {
|
|
||||||
// Style speaker labels (LUKE:, REGGIE:, etc.)
|
|
||||||
const labeled = p.replace(/^([A-Z][A-Z\s'-]+?):\s*/, '<span class="speaker-label">$1:</span> ');
|
|
||||||
return `<p>${labeled.replace(/\n/g, '<br>')}</p>`;
|
|
||||||
}).join('');
|
|
||||||
document.getElementById('transcript-body').innerHTML = html;
|
|
||||||
} catch (e) {
|
|
||||||
document.getElementById('transcript-body').innerHTML = '<p class="transcript-unavailable">Transcript not yet available for this episode.</p>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audio player controls
|
|
||||||
audio.addEventListener('play', () => updatePlayIcons(true));
|
|
||||||
audio.addEventListener('pause', () => updatePlayIcons(false));
|
|
||||||
audio.addEventListener('ended', () => updatePlayIcons(false));
|
|
||||||
audio.addEventListener('timeupdate', () => {
|
|
||||||
if (audio.duration) {
|
|
||||||
playerProgressFill.style.width = (audio.currentTime / audio.duration * 100) + '%';
|
|
||||||
playerTime.textContent = `${formatTime(audio.currentTime)} / ${formatTime(audio.duration)}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function updatePlayIcons(playing) {
|
|
||||||
const iconPlay = playerPlayBtn.querySelector('.icon-play');
|
|
||||||
const iconPause = playerPlayBtn.querySelector('.icon-pause');
|
|
||||||
if (iconPlay) iconPlay.style.display = playing ? 'none' : 'block';
|
|
||||||
if (iconPause) iconPause.style.display = playing ? 'block' : 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
playerPlayBtn.addEventListener('click', () => {
|
|
||||||
if (audio.src) { audio.paused ? audio.play() : audio.pause(); }
|
|
||||||
});
|
|
||||||
|
|
||||||
playerProgress.addEventListener('click', (e) => {
|
|
||||||
if (audio.duration) {
|
|
||||||
const rect = playerProgress.getBoundingClientRect();
|
|
||||||
audio.currentTime = ((e.clientX - rect.left) / rect.width) * audio.duration;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>How It Works — Luke at the Roost</title>
|
<title>How It Works — Luke at the Roost</title>
|
||||||
<meta name="description" content="How Luke at the Roost works: AI-generated callers with unique personalities, real phone calls, voice synthesis, multi-stem recording, and automated post-production.">
|
<meta name="description" content="How Luke at the Roost works: AI-generated callers with structured personalities, comedy-tuned call shapes, a live research intern, voice-personality matching, multi-stem recording, and automated post-production.">
|
||||||
<meta name="theme-color" content="#1a1209">
|
<meta name="theme-color" content="#1a1209">
|
||||||
<link rel="canonical" href="https://lukeattheroost.com/how-it-works">
|
<link rel="canonical" href="https://lukeattheroost.com/how-it-works">
|
||||||
|
|
||||||
@@ -28,11 +28,11 @@
|
|||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
||||||
<link rel="stylesheet" href="css/style.css?v=2">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
|
|
||||||
<!-- Structured Data -->
|
<!-- Structured Data -->
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{
|
[{
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "TechArticle",
|
"@type": "TechArticle",
|
||||||
"headline": "How Luke at the Roost Works",
|
"headline": "How Luke at the Roost Works",
|
||||||
@@ -53,22 +53,164 @@
|
|||||||
"url": "https://lukeattheroost.com"
|
"url": "https://lukeattheroost.com"
|
||||||
},
|
},
|
||||||
"inLanguage": "en"
|
"inLanguage": "en"
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "BreadcrumbList",
|
||||||
|
"itemListElement": [
|
||||||
|
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://lukeattheroost.com" },
|
||||||
|
{ "@type": "ListItem", "position": 2, "name": "How It Works" }
|
||||||
|
]
|
||||||
|
}]
|
||||||
</script>
|
</script>
|
||||||
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<!-- Nav -->
|
<a href="#main-content" class="skip-link">Skip to content</a>
|
||||||
<nav class="page-nav">
|
|
||||||
<a href="/" class="nav-home">Luke at the Roost</a>
|
<nav class="site-nav">
|
||||||
|
<a href="/" class="site-nav-brand">Luke at the Roost</a>
|
||||||
|
<div class="site-nav-links">
|
||||||
|
<a href="/how-it-works" aria-current="page">How It Works</a>
|
||||||
|
<a href="/clips">Clips</a>
|
||||||
|
<a href="/stats">Stats</a>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<main id="main-content">
|
||||||
|
|
||||||
<!-- Page Header -->
|
<!-- Page Header -->
|
||||||
<section class="page-header">
|
<section class="page-header">
|
||||||
<h1>How It Works</h1>
|
<h1>How It Works</h1>
|
||||||
<p class="page-subtitle">Every caller on the show is a one-of-a-kind character — generated in real time by a custom-built AI system. Here's a peek behind the curtain.</p>
|
<p class="page-subtitle">Every caller on the show is a one-of-a-kind character — generated in real time by a custom-built AI system. Here's a peek behind the curtain.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Steps -->
|
||||||
|
<section class="hiw-section">
|
||||||
|
<h2>The Anatomy of an AI Caller</h2>
|
||||||
|
|
||||||
|
<div class="hiw-steps">
|
||||||
|
<div class="hiw-step">
|
||||||
|
<div class="hiw-step-number">1</div>
|
||||||
|
<div class="hiw-step-content">
|
||||||
|
<h3>A Person Is Born</h3>
|
||||||
|
<p>Every caller starts as a blank slate. The system generates a complete identity: name, age, job, hometown, and personality. Each caller gets a unique speaking style — some ramble, some are blunt, some deflect with humor. They have relationships, vehicles, strong food opinions, nostalgic memories, and reasons for being up this late. They know what they were watching on TV, what errand they ran today, and what song was on the radio before they called.</p>
|
||||||
|
<p>But it goes deeper than backstory. Every caller is built with a structured call shape — maybe an escalating reveal where they start casual and drop a bombshell halfway through, a bait-and-switch where the real issue isn't what they said at first, or a slow burn that builds to an emotional peak. They have energy levels, emotional states, and signature details — a phrase they keep coming back to, a nervous tic in how they talk, a specific detail that makes the whole thing feel real. And each caller is matched to a voice that fits their personality. A 60-year-old trucker from Lordsburg doesn't sound like a 23-year-old barista from Tucson.</p>
|
||||||
|
<p>Some callers become regulars. The system tracks returning callers across episodes — they remember past conversations, reference things they talked about before, and their stories evolve over time. You'll hear Leon check in about going back to school, or Shaniqua update you on her situation at work. They're not reset between shows.</p>
|
||||||
|
<p>And some callers are drunk, high, or flat-out unhinged. They'll call with conspiracy theories about pigeons being government drones, existential crises about whether fish know they're wet, or to confess they accidentally set their kitchen on fire trying to make grilled cheese at 3 AM.</p>
|
||||||
|
<div class="hiw-detail-grid">
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Unique Names</span>
|
||||||
|
<span class="hiw-detail-value">160</span>
|
||||||
|
</div>
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Voice Profiles</span>
|
||||||
|
<span class="hiw-detail-value">68</span>
|
||||||
|
</div>
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Call Shapes</span>
|
||||||
|
<span class="hiw-detail-value">8 types</span>
|
||||||
|
</div>
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Returning Regulars</span>
|
||||||
|
<span class="hiw-detail-value">12 callers</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hiw-step">
|
||||||
|
<div class="hiw-step-number">2</div>
|
||||||
|
<div class="hiw-step-content">
|
||||||
|
<h3>They Know Their World</h3>
|
||||||
|
<p>Callers know real facts about where they live — the restaurants, the highways, the local gossip. The system has deep knowledge of 55 real towns across New Mexico and Arizona. When a caller says they're from Lordsburg, they actually know about the Shakespeare ghost town and the drive to Deming. They know the current weather outside their window, what day of the week it is, whether it's monsoon season or chile harvest. They have strong opinions about where to get the best green chile and get nostalgic about how their town used to be. The system also pulls in real-time news so callers can reference things that actually happened today.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hiw-step">
|
||||||
|
<div class="hiw-step-number">3</div>
|
||||||
|
<div class="hiw-step-content">
|
||||||
|
<h3>They Have a Reason to Call</h3>
|
||||||
|
<p>Some callers have a problem — a fight with a neighbor, a situation at work, something weighing on them at 2 AM. Others call to geek out about Severance, argue about poker strategy, or share something they read about quantum physics. The system draws from over 1,000 unique calling reasons across dozens of categories — problems, stories, advice-seeking, gossip, and deep-dive topics. Every caller has a purpose, not just a script.</p>
|
||||||
|
<p>The whole thing is tuned for comedy. Not "AI tries to be funny" comedy — more like the energy of late-night call-in radio meets stand-up meets the kind of confessions you only hear at 2 AM. Some calls are genuinely heartfelt. Some are absurd. Some start serious and go completely sideways. The system knows how to build a call for comedic timing — when to hold back a detail, when to escalate, when to let the awkward silence do the work. It's not random chaos; it's structured chaos.</p>
|
||||||
|
<div class="hiw-split-stat">
|
||||||
|
<div class="hiw-stat">
|
||||||
|
<span class="hiw-stat-number">70%</span>
|
||||||
|
<span class="hiw-stat-label">Need advice</span>
|
||||||
|
</div>
|
||||||
|
<div class="hiw-stat">
|
||||||
|
<span class="hiw-stat-number">30%</span>
|
||||||
|
<span class="hiw-stat-label">Want to talk about something</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hiw-step">
|
||||||
|
<div class="hiw-step-number">4</div>
|
||||||
|
<div class="hiw-step-content">
|
||||||
|
<h3>The Conversation Is Real</h3>
|
||||||
|
<p>Luke talks to each caller using push-to-talk, just like a real radio show. His voice is transcribed in real time, sent to an AI that responds in character, and then converted to speech using a voice engine — all in a few seconds. The AI doesn't just answer questions; it reacts, gets emotional, goes on tangents, and remembers what was said earlier in the show.</p>
|
||||||
|
<p>Callers don't just exist in isolation — the show tracks what's been discussed and matches callers thematically. If someone just called about a messy divorce, the next caller who references marriage didn't pick that topic randomly. The system scores previous callers by topic overlap and decides whether the new caller should reference them, disagree with them, or build on what they said. It tracks the show's overall energy so the pacing doesn't flatline — a heavy emotional call might be followed by something lighter, and vice versa.</p>
|
||||||
|
<p>And when a call has run its course, Luke can hit "Wrap It Up" — a signal that tells the caller to wind things down gracefully. Instead of an abrupt hang-up, the caller gets the hint and starts wrapping up their thought, says their goodbyes, and exits naturally. Just like a real radio host giving the "time's up" hand signal through the glass.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hiw-step">
|
||||||
|
<div class="hiw-step-number">5</div>
|
||||||
|
<div class="hiw-step-content">
|
||||||
|
<h3>Real Callers Call In Too</h3>
|
||||||
|
<p>When you dial 208-439-LUKE, your call goes into a live queue. Luke sees you waiting and can take your call right from the control room. Your voice streams in real time — no pre-recording, no delay. You're live on the show, talking to Luke, and the AI callers might even react to what you said. And if Luke isn't live, you can leave a voicemail — it gets transcribed and may get played on a future episode.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hiw-step">
|
||||||
|
<div class="hiw-step-number">6</div>
|
||||||
|
<div class="hiw-step-content">
|
||||||
|
<h3>Listener Emails</h3>
|
||||||
|
<p>Listeners can send emails to <a href="mailto:submissions@lukeattheroost.com" style="color:var(--accent)">submissions@lukeattheroost.com</a> and have them read on the show. A background poller checks for new messages every 30 seconds — they show up in the control room as soon as they arrive. Luke can read them himself on the mic, or hit a button to have an AI voice read them aloud on the caller channel. It's like a call-in show meets a letters segment — listeners who can't call in can still be part of the conversation.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hiw-step">
|
||||||
|
<div class="hiw-step-number">7</div>
|
||||||
|
<div class="hiw-step-content">
|
||||||
|
<h3>Devon the Intern</h3>
|
||||||
|
<p>Every show needs someone to yell at. Devon is the show's intern — a 23-year-old NMSU grad who's way too eager, occasionally useful, and frequently wrong. He's not a caller; he's a permanent fixture of the show. When Luke needs a fact checked, a topic researched, or someone to blame for a technical issue, Devon's there.</p>
|
||||||
|
<p>Devon has real tools. He can search the web, pull up news headlines, look things up on Wikipedia, and read articles — all live during the show. When a caller claims that octopuses have three hearts, Devon's already looking it up. Sometimes he interjects on his own when he thinks he has something useful to add. Sometimes he's right. Sometimes Luke tells him to shut up. He monitors conversations in the background and pipes up with suggestions that the host can play or dismiss. He's the kind of intern who tries really hard and occasionally nails it.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hiw-step">
|
||||||
|
<div class="hiw-step-number">8</div>
|
||||||
|
<div class="hiw-step-content">
|
||||||
|
<h3>The Control Room</h3>
|
||||||
|
<p>The entire show runs through a custom-built control panel. Luke manages callers, plays music and sound effects, runs ads and station idents, monitors the call queue, and controls everything from one screen. Audio is routed across seven independent channels simultaneously — host mic, AI caller voices, live phone audio, music, sound effects, ads, and station idents all on separate tracks. The website shows a live on-air indicator so listeners know when to call in.</p>
|
||||||
|
<div class="hiw-detail-grid">
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Audio Channels</span>
|
||||||
|
<span class="hiw-detail-value">7 independent</span>
|
||||||
|
</div>
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Caller Slots</span>
|
||||||
|
<span class="hiw-detail-value">10 per session</span>
|
||||||
|
</div>
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Phone System</span>
|
||||||
|
<span class="hiw-detail-value">VoIP + WebSocket</span>
|
||||||
|
</div>
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Live Status</span>
|
||||||
|
<span class="hiw-detail-value">Real-time CDN</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Overview -->
|
<!-- Overview -->
|
||||||
<section class="hiw-section">
|
<section class="hiw-section">
|
||||||
<div class="hiw-card hiw-hero-card">
|
<div class="hiw-card hiw-hero-card">
|
||||||
@@ -94,6 +236,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<span>Real Callers</span>
|
<span>Real Callers</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="diagram-box diagram-accent">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="16" rx="2"/><path d="M2 6l10 7 10-7"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Voicemails</span>
|
||||||
|
</div>
|
||||||
|
<div class="diagram-box diagram-accent">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Listener Emails</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="diagram-arrow">↓</div>
|
<div class="diagram-arrow">↓</div>
|
||||||
<!-- Row 2: Control Room -->
|
<!-- Row 2: Control Room -->
|
||||||
@@ -132,6 +286,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<span>Audio Router</span>
|
<span>Audio Router</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="diagram-box">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Phone System</span>
|
||||||
|
</div>
|
||||||
|
<div class="diagram-box">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M9 21V9"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Ad Engine</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Row 4: Recording -->
|
<!-- Row 4: Recording -->
|
||||||
<div class="diagram-row">
|
<div class="diagram-row">
|
||||||
@@ -187,11 +353,23 @@
|
|||||||
</div>
|
</div>
|
||||||
<span>Website</span>
|
<span>Website</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="diagram-box">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="11" rx="2"/><path d="M7 21h10"/><path d="M12 14v7"/><polygon points="10 8 16 11 10 14 10 8"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Social Clips</span>
|
||||||
|
</div>
|
||||||
|
<div class="diagram-box">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Monitoring</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="diagram-arrow">↓</div>
|
<div class="diagram-arrow">↓</div>
|
||||||
<!-- Row 7: Distribution -->
|
<!-- Row 7: Distribution -->
|
||||||
<div class="diagram-label">Distribution</div>
|
<div class="diagram-label">Distribution</div>
|
||||||
<div class="diagram-row diagram-row-split">
|
<div class="diagram-row-compact">
|
||||||
<div class="diagram-box diagram-accent">
|
<div class="diagram-box diagram-accent">
|
||||||
<div class="diagram-icon">
|
<div class="diagram-icon">
|
||||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z"/></svg>
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z"/></svg>
|
||||||
@@ -216,6 +394,54 @@
|
|||||||
</div>
|
</div>
|
||||||
<span>RSS</span>
|
<span>RSS</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="diagram-box diagram-accent">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm3.1 14.5c-1.7 1-3.8.6-4.8-1.1-1-1.7-.6-3.8 1.1-4.8 1.7-1 3.8-.6 4.8 1.1 1 1.7.5 3.8-1.1 4.8z"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Instagram</span>
|
||||||
|
</div>
|
||||||
|
<div class="diagram-box diagram-accent">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Facebook</span>
|
||||||
|
</div>
|
||||||
|
<div class="diagram-box diagram-accent">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 568 501" fill="currentColor"><path d="M123.121 33.664C188.241 82.553 258.281 181.68 284 234.873c25.719-53.192 95.759-152.32 160.879-201.21C491.866-1.611 568-28.906 568 57.947c0 17.346-9.945 145.713-15.778 166.555-20.275 72.453-94.155 90.933-159.875 79.748C507.222 323.8 536.444 388.56 473.333 453.32c-119.86 122.992-172.272-30.859-185.702-70.281-2.462-7.227-3.614-10.608-3.631-7.733-.017-2.875-1.169.506-3.631 7.733-13.43 39.422-65.842 193.273-185.702 70.281-63.111-64.76-33.89-129.52 80.986-149.071-65.72 11.185-139.6-7.295-159.875-79.748C10.945 203.659 1 75.291 1 57.946 1-28.906 76.134-1.612 123.121 33.664z"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Bluesky</span>
|
||||||
|
</div>
|
||||||
|
<div class="diagram-box diagram-accent">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054 19.648 19.648 0 0 0 4.636.528c.164 0 .329 0 .494-.002 1.694-.042 3.48-.152 5.12-.554 2.21-.543 4.137-2.186 4.348-4.55.162-1.808.21-3.627.142-5.43-.02-.6-.168-1.874-.168-1.874z"/><path d="M19.903 7.515v5.834c0 1.226-.996 2.222-2.222 2.222h-.796c-1.226 0-2.222-.996-2.222-2.222V7.628c0-1.226.996-2.222 2.222-2.222h.796c.122 0 .242.01.36.03 1.076.164 1.862 1.098 1.862 2.192zM9.337 7.515v5.834c0 1.226-.996 2.222-2.222 2.222h-.796c-1.226 0-2.222-.996-2.222-2.222V7.628c0-1.226.996-2.222 2.222-2.222h.796c.122 0 .242.01.36.03 1.076.164 1.862 1.098 1.862 2.192z" fill="#fff"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Mastodon</span>
|
||||||
|
</div>
|
||||||
|
<div class="diagram-box diagram-accent">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12.186.31a.27.27 0 0 0-.372 0C8.46 3.487 2.666 9.93 2.666 15.042c0 5.176 4.183 8.958 9.334 8.958s9.334-3.782 9.334-8.958c0-5.112-5.794-11.555-9.148-14.732z"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Nostr</span>
|
||||||
|
</div>
|
||||||
|
<div class="diagram-box diagram-accent">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>LinkedIn</span>
|
||||||
|
</div>
|
||||||
|
<div class="diagram-box diagram-accent">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12.159 2c-5.543 0-9.94 4.486-9.94 9.94 0 2.16.72 4.148 1.897 5.852l-1.26 4.463 4.612-1.188A9.882 9.882 0 0 0 12.16 22c5.543 0 9.94-4.486 9.94-9.94 0-5.543-4.486-10.06-9.94-10.06z"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>Threads</span>
|
||||||
|
</div>
|
||||||
|
<div class="diagram-box diagram-accent">
|
||||||
|
<div class="diagram-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z"/></svg>
|
||||||
|
</div>
|
||||||
|
<span>TikTok</span>
|
||||||
|
</div>
|
||||||
<div class="diagram-box diagram-accent">
|
<div class="diagram-box diagram-accent">
|
||||||
<div class="diagram-icon">
|
<div class="diagram-icon">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 20V10"/><path d="M12 20V4"/><path d="M6 20v-6"/></svg>
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 20V10"/><path d="M12 20V4"/><path d="M6 20v-6"/></svg>
|
||||||
@@ -227,122 +453,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Steps -->
|
|
||||||
<section class="hiw-section">
|
|
||||||
<h2>The Anatomy of an AI Caller</h2>
|
|
||||||
|
|
||||||
<div class="hiw-steps">
|
|
||||||
<div class="hiw-step">
|
|
||||||
<div class="hiw-step-number">1</div>
|
|
||||||
<div class="hiw-step-content">
|
|
||||||
<h3>A Person Is Born</h3>
|
|
||||||
<p>Every caller starts as a blank slate. The system generates a complete identity: name, age, job, hometown, and personality. Each caller gets a unique speaking style — some ramble, some are blunt, some deflect with humor. They have relationships, vehicles, strong food opinions, nostalgic memories, and reasons for being up this late. They know what they were watching on TV, what errand they ran today, and what song was on the radio before they called.</p>
|
|
||||||
<p>Some callers become regulars. The system tracks returning callers across episodes — they remember past conversations, reference things they talked about before, and their stories evolve over time. You'll hear Carla update you on her divorce, or Carl check in about his gambling recovery. They're not reset between shows.</p>
|
|
||||||
<div class="hiw-detail-grid">
|
|
||||||
<div class="hiw-detail">
|
|
||||||
<span class="hiw-detail-label">Unique Names</span>
|
|
||||||
<span class="hiw-detail-value">160 names</span>
|
|
||||||
</div>
|
|
||||||
<div class="hiw-detail">
|
|
||||||
<span class="hiw-detail-label">Personality Layers</span>
|
|
||||||
<span class="hiw-detail-value">30+</span>
|
|
||||||
</div>
|
|
||||||
<div class="hiw-detail">
|
|
||||||
<span class="hiw-detail-label">Towns with Real Knowledge</span>
|
|
||||||
<span class="hiw-detail-value">32</span>
|
|
||||||
</div>
|
|
||||||
<div class="hiw-detail">
|
|
||||||
<span class="hiw-detail-label">Returning Regulars</span>
|
|
||||||
<span class="hiw-detail-value">12+ callers</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hiw-step">
|
|
||||||
<div class="hiw-step-number">2</div>
|
|
||||||
<div class="hiw-step-content">
|
|
||||||
<h3>They Know Their World</h3>
|
|
||||||
<p>Callers know real facts about where they live — the restaurants, the highways, the local gossip. When a caller says they're from Lordsburg, they actually know about the Shakespeare ghost town and the drive to Deming. They know the current weather outside their window, what day of the week it is, whether it's monsoon season or chile harvest. They have strong opinions about where to get the best green chile and get nostalgic about how their town used to be. The system also pulls in real-time news so callers can reference things that actually happened today.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hiw-step">
|
|
||||||
<div class="hiw-step-number">3</div>
|
|
||||||
<div class="hiw-step-content">
|
|
||||||
<h3>They Have a Reason to Call</h3>
|
|
||||||
<p>Some callers have a problem — a fight with a neighbor, a situation at work, something weighing on them at 2 AM. Others call to geek out about Severance, argue about poker strategy, or share something they read about quantum physics. Every caller has a purpose, not just a script.</p>
|
|
||||||
<div class="hiw-split-stat">
|
|
||||||
<div class="hiw-stat">
|
|
||||||
<span class="hiw-stat-number">70%</span>
|
|
||||||
<span class="hiw-stat-label">Need advice</span>
|
|
||||||
</div>
|
|
||||||
<div class="hiw-stat">
|
|
||||||
<span class="hiw-stat-number">30%</span>
|
|
||||||
<span class="hiw-stat-label">Want to talk about something</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hiw-step">
|
|
||||||
<div class="hiw-step-number">4</div>
|
|
||||||
<div class="hiw-step-content">
|
|
||||||
<h3>The Conversation Is Real</h3>
|
|
||||||
<p>Luke talks to each caller using push-to-talk, just like a real radio show. His voice is transcribed in real time, sent to an AI that responds in character, and then converted to speech using a voice engine — all in a few seconds. The AI doesn't just answer questions; it reacts, gets emotional, goes on tangents, and remembers what was said earlier in the show. Callers even react to previous callers — "Hey Luke, I heard that guy Tony earlier and I got to say, he's full of it." It makes the show feel like a living community, not isolated calls.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hiw-step">
|
|
||||||
<div class="hiw-step-number">5</div>
|
|
||||||
<div class="hiw-step-content">
|
|
||||||
<h3>Real Callers Call In Too</h3>
|
|
||||||
<p>When you dial 208-439-LUKE, your call goes into a live queue. Luke sees you waiting and can take your call right from the control room. Your voice streams in real time — no pre-recording, no delay. You're live on the show, talking to Luke, and the AI callers might even react to what you said.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hiw-step">
|
|
||||||
<div class="hiw-step-number">6</div>
|
|
||||||
<div class="hiw-step-content">
|
|
||||||
<h3>The Control Room</h3>
|
|
||||||
<p>The entire show runs through a custom-built control panel. Luke manages callers, plays music and sound effects, runs ads, monitors the call queue, and controls everything from one screen. Audio is routed across multiple channels simultaneously — caller voices, music, sound effects, and live phone audio all on separate tracks. The website shows a live on-air indicator so listeners know when to call in.</p>
|
|
||||||
<div class="hiw-detail-grid">
|
|
||||||
<div class="hiw-detail">
|
|
||||||
<span class="hiw-detail-label">Audio Channels</span>
|
|
||||||
<span class="hiw-detail-value">5 independent</span>
|
|
||||||
</div>
|
|
||||||
<div class="hiw-detail">
|
|
||||||
<span class="hiw-detail-label">Caller Slots</span>
|
|
||||||
<span class="hiw-detail-value">10 per session</span>
|
|
||||||
</div>
|
|
||||||
<div class="hiw-detail">
|
|
||||||
<span class="hiw-detail-label">Phone System</span>
|
|
||||||
<span class="hiw-detail-value">VoIP + WebSocket</span>
|
|
||||||
</div>
|
|
||||||
<div class="hiw-detail">
|
|
||||||
<span class="hiw-detail-label">Live Status</span>
|
|
||||||
<span class="hiw-detail-value">Real-time CDN</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- Post-Production Pipeline -->
|
<!-- Post-Production Pipeline -->
|
||||||
<section class="hiw-section">
|
<section class="hiw-section">
|
||||||
<h2>From Live Show to Podcast</h2>
|
<h2>From Live Show to Podcast</h2>
|
||||||
|
|
||||||
<div class="hiw-steps">
|
<div class="hiw-steps">
|
||||||
<div class="hiw-step">
|
<div class="hiw-step">
|
||||||
<div class="hiw-step-number">7</div>
|
<div class="hiw-step-number">9</div>
|
||||||
<div class="hiw-step-content">
|
<div class="hiw-step-content">
|
||||||
<h3>Multi-Stem Recording</h3>
|
<h3>Multi-Stem Recording</h3>
|
||||||
<p>During every show, the system records five separate audio stems simultaneously: host microphone, AI caller voices, music, sound effects, and ads. Each stem is captured as an independent WAV file with sample-accurate alignment. This gives full control over the final mix — like having a recording studio's multitrack session, not just a flat recording.</p>
|
<p>During every show, the system records six separate audio stems simultaneously: host microphone, AI caller voices, music, sound effects, ads, and station idents. Each stem is captured as an independent WAV file with sample-accurate alignment. This gives full control over the final mix — like having a recording studio's multitrack session, not just a flat recording.</p>
|
||||||
<div class="hiw-detail-grid">
|
<div class="hiw-detail-grid">
|
||||||
<div class="hiw-detail">
|
<div class="hiw-detail">
|
||||||
<span class="hiw-detail-label">Stems Captured</span>
|
<span class="hiw-detail-label">Stems Captured</span>
|
||||||
<span class="hiw-detail-value">5 parallel</span>
|
<span class="hiw-detail-value">6 parallel</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="hiw-detail">
|
<div class="hiw-detail">
|
||||||
<span class="hiw-detail-label">Format</span>
|
<span class="hiw-detail-label">Format</span>
|
||||||
@@ -361,7 +485,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hiw-step">
|
<div class="hiw-step">
|
||||||
<div class="hiw-step-number">8</div>
|
<div class="hiw-step-number">10</div>
|
||||||
|
<div class="hiw-step-content">
|
||||||
|
<h3>Dialog Editing in REAPER</h3>
|
||||||
|
<p>Before the automated pipeline runs, the raw stems are loaded into REAPER for dialog editing. A custom Lua script analyzes voice tracks to detect silence gaps — the dead air between caller responses, TTS latency pauses, and gaps where Luke is reading the control room. The script strips these silences and ripple-edits all tracks in sync so ads, idents, and music shift with the dialog cuts. Protected regions marked as ads or idents are preserved — the script knows not to remove silence during an ad break even if the voice tracks are quiet. This tightens a raw two-hour session into a focused episode without cutting any content.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hiw-step">
|
||||||
|
<div class="hiw-step-number">11</div>
|
||||||
<div class="hiw-step-content">
|
<div class="hiw-step-content">
|
||||||
<h3>Post-Production Pipeline</h3>
|
<h3>Post-Production Pipeline</h3>
|
||||||
<p>Once the show ends, a 15-step automated pipeline processes the raw stems into a broadcast-ready episode. Ads and sound effects are hard-limited to prevent clipping. The host mic gets a high-pass filter, de-essing, and breath reduction. Voice tracks are compressed — the host gets aggressive spoken-word compression for consistent levels, callers get telephone EQ to sound like real phone calls. All stems are level-matched, music is ducked under dialog and muted during ads, then everything is mixed to stereo with panning and width. A bus compressor glues the final mix together before silence trimming, fades, and EBU R128 loudness normalization.</p>
|
<p>Once the show ends, a 15-step automated pipeline processes the raw stems into a broadcast-ready episode. Ads and sound effects are hard-limited to prevent clipping. The host mic gets a high-pass filter, de-essing, and breath reduction. Voice tracks are compressed — the host gets aggressive spoken-word compression for consistent levels, callers get telephone EQ to sound like real phone calls. All stems are level-matched, music is ducked under dialog and muted during ads, then everything is mixed to stereo with panning and width. A bus compressor glues the final mix together before silence trimming, fades, and EBU R128 loudness normalization.</p>
|
||||||
@@ -387,14 +519,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hiw-step">
|
<div class="hiw-step">
|
||||||
<div class="hiw-step-number">9</div>
|
<div class="hiw-step-number">12</div>
|
||||||
<div class="hiw-step-content">
|
<div class="hiw-step-content">
|
||||||
<h3>Automated Publishing</h3>
|
<h3>Automated Publishing</h3>
|
||||||
<p>A single command takes a finished episode and handles everything: the audio is transcribed using speech recognition to generate full-text transcripts, then an LLM analyzes the transcript to write the episode title, description, and chapter markers with timestamps. The episode is uploaded to the podcast server, chapters and transcripts are attached to the metadata, and all media is synced to a global CDN so listeners everywhere get fast downloads.</p>
|
<p>A single command takes a finished episode and handles everything: the audio is transcribed using MLX Whisper running on Apple Silicon GPU to generate full-text transcripts, then an LLM analyzes the transcript to write the episode title, description, and chapter markers with timestamps. The episode is uploaded to the podcast server and directly to YouTube with chapters baked into the description. Chapters and transcripts are attached to the RSS metadata, all media is synced to a global CDN, and social posts are pushed to eight platforms — all from one command.</p>
|
||||||
<div class="hiw-detail-grid">
|
<div class="hiw-detail-grid">
|
||||||
<div class="hiw-detail">
|
<div class="hiw-detail">
|
||||||
<span class="hiw-detail-label">Transcription</span>
|
<span class="hiw-detail-label">Transcription</span>
|
||||||
<span class="hiw-detail-value">Whisper AI</span>
|
<span class="hiw-detail-value">MLX Whisper (GPU)</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="hiw-detail">
|
<div class="hiw-detail">
|
||||||
<span class="hiw-detail-label">Metadata</span>
|
<span class="hiw-detail-label">Metadata</span>
|
||||||
@@ -413,7 +545,33 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hiw-step">
|
<div class="hiw-step">
|
||||||
<div class="hiw-step-number">10</div>
|
<div class="hiw-step-number">13</div>
|
||||||
|
<div class="hiw-step-content">
|
||||||
|
<h3>Automated Social Clips</h3>
|
||||||
|
<p>No manual editing, no scheduling tools. After each episode, an LLM reads the full transcript and picks the best moments — funny exchanges, wild confessions, heated debates. Each clip is automatically extracted, transcribed with word-level timestamps, then polished by a second LLM pass that fixes punctuation, capitalization, and misheard words while preserving timing. The clips are rendered as vertical video with speaker-labeled captions and the show's branding. A third LLM writes platform-specific descriptions and hashtags. Then clips are uploaded directly to YouTube Shorts and Bluesky via their APIs, and pushed to Instagram Reels, Facebook Reels, Mastodon, Nostr, LinkedIn, Threads, and TikTok — nine platforms, zero manual work.</p>
|
||||||
|
<div class="hiw-detail-grid">
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Human Effort</span>
|
||||||
|
<span class="hiw-detail-value">Zero</span>
|
||||||
|
</div>
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Video Format</span>
|
||||||
|
<span class="hiw-detail-value">1080x1920 MP4</span>
|
||||||
|
</div>
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Captions</span>
|
||||||
|
<span class="hiw-detail-value">LLM-polished</span>
|
||||||
|
</div>
|
||||||
|
<div class="hiw-detail">
|
||||||
|
<span class="hiw-detail-label">Simultaneous Push</span>
|
||||||
|
<span class="hiw-detail-value">9 platforms</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hiw-step">
|
||||||
|
<div class="hiw-step-number">14</div>
|
||||||
<div class="hiw-step-content">
|
<div class="hiw-step-content">
|
||||||
<h3>Global Distribution</h3>
|
<h3>Global Distribution</h3>
|
||||||
<p>Episodes are served through a CDN edge network for fast, reliable playback worldwide. The RSS feed is automatically updated and picked up by Spotify, Apple Podcasts, YouTube, and every other podcast app. The website pulls the live feed to show episodes with embedded playback, full transcripts, and chapter navigation — all served through Cloudflare with edge caching. From recording to available on every platform, the whole pipeline is automated end-to-end.</p>
|
<p>Episodes are served through a CDN edge network for fast, reliable playback worldwide. The RSS feed is automatically updated and picked up by Spotify, Apple Podcasts, YouTube, and every other podcast app. The website pulls the live feed to show episodes with embedded playback, full transcripts, and chapter navigation — all served through Cloudflare with edge caching. From recording to available on every platform, the whole pipeline is automated end-to-end.</p>
|
||||||
@@ -470,7 +628,7 @@
|
|||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
|
||||||
</div>
|
</div>
|
||||||
<h3>They Listen to Each Other</h3>
|
<h3>They Listen to Each Other</h3>
|
||||||
<p>Callers aren't isolated — they hear what happened earlier in the show. A caller might disagree with the last guy, back someone up, or call in specifically because of something another caller said. The show builds on itself.</p>
|
<p>Callers aren't isolated — the system matches callers thematically to what's already been discussed. A caller might disagree with the last guy, back someone up, or call in because something another caller said hit close to home. The show tracks energy and pacing so conversations build naturally, not randomly.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="hiw-feature">
|
<div class="hiw-feature">
|
||||||
<div class="hiw-feature-icon">
|
<div class="hiw-feature-icon">
|
||||||
@@ -489,6 +647,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Post-Production Automation Video -->
|
||||||
|
<section class="hiw-section">
|
||||||
|
<h2>Post-Production in Action</h2>
|
||||||
|
<div class="hiw-hero-card">
|
||||||
|
<video class="hiw-video" controls playsinline preload="metadata" poster="">
|
||||||
|
<source src="https://cdn.lukeattheroost.com/videos/reaper-postprod.mp4" type="video/mp4">
|
||||||
|
</video>
|
||||||
|
<p class="hiw-video-caption">The entire post-production pipeline runs automatically through Reaper scripting. Silence removal, ad ducking, and EBU R128 loudness normalization — all triggered with a single command when the show ends.</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- CTA -->
|
<!-- CTA -->
|
||||||
<section class="hiw-section hiw-cta">
|
<section class="hiw-section hiw-cta">
|
||||||
<p>Want to hear it for yourself?</p>
|
<p>Want to hear it for yourself?</p>
|
||||||
@@ -496,33 +665,12 @@
|
|||||||
<div class="hiw-cta-phone">
|
<div class="hiw-cta-phone">
|
||||||
Or call in live: <strong>208-439-LUKE</strong>
|
Or call in live: <strong>208-439-LUKE</strong>
|
||||||
</div>
|
</div>
|
||||||
|
<a href="https://ko-fi.com/lukemacneil" target="_blank" rel="noopener" class="hiw-cta-support">Support the Show</a>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Footer -->
|
</main>
|
||||||
<footer class="footer">
|
|
||||||
<div class="footer-links">
|
|
||||||
<a href="/">Home</a>
|
|
||||||
<a href="/stats">Stats</a>
|
|
||||||
<a href="https://discord.gg/5CnQZxDM" target="_blank" rel="noopener">Discord</a>
|
|
||||||
<a href="https://www.facebook.com/profile.php?id=61588191627949" target="_blank" rel="noopener">Facebook</a>
|
|
||||||
<a href="https://x.com/lukeattheroost" target="_blank" rel="noopener">X</a>
|
|
||||||
<a href="https://bsky.app/profile/lukeattheroost.bsky.social" target="_blank" rel="noopener">Bluesky</a>
|
|
||||||
<a href="https://mastodon.macneilmediagroup.com/@lukeattheroost" target="_blank" rel="me noopener">Mastodon</a>
|
|
||||||
<a href="https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF?si=f990713adce84ba4" target="_blank" rel="noopener">Spotify</a>
|
|
||||||
<a href="https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-" target="_blank" rel="noopener">YouTube</a>
|
|
||||||
<a href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml" target="_blank" rel="noopener">RSS</a>
|
|
||||||
</div>
|
|
||||||
<div class="footer-projects">
|
|
||||||
<span class="footer-projects-label">More from Luke</span>
|
|
||||||
<div class="footer-projects-links">
|
|
||||||
<a href="https://macneilmediagroup.com" target="_blank" rel="noopener">MacNeil Media Group</a>
|
|
||||||
<a href="https://prints.macneilmediagroup.com" target="_blank" rel="noopener">Photography Prints</a>
|
|
||||||
<a href="https://youtube.com/lukemacneil" target="_blank" rel="noopener">YouTube</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="footer-contact">Sales & Collaboration: <a href="mailto:luke@macneilmediagroup.com">luke@macneilmediagroup.com</a></p>
|
|
||||||
<p>© 2026 Luke at the Roost · <a href="/privacy">Privacy Policy</a></p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
|
<footer class="footer"></footer>
|
||||||
|
<script src="js/footer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 28 KiB |
@@ -4,20 +4,21 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Luke at the Roost — AI Call-In Comedy Podcast</title>
|
<title>Luke at the Roost — AI Call-In Comedy Podcast</title>
|
||||||
<meta name="description" content="Late-night call-in radio from a desert hermit's RV. Real callers and AI-generated characters talk to Luke about life, love, and everything in between. Call in: 208-439-LUKE.">
|
<meta name="description" content="AI-powered late-night call-in comedy podcast. Real callers and AI-generated characters talk to Luke MacNeil about life, love, and everything in between. 37+ episodes. Call in: 208-439-LUKE.">
|
||||||
|
<meta name="keywords" content="AI podcast, comedy podcast, call-in radio, AI-generated callers, late-night radio, Luke MacNeil, talk show, AI comedy, artificial intelligence podcast, call-in podcast">
|
||||||
<meta name="theme-color" content="#1a1209">
|
<meta name="theme-color" content="#1a1209">
|
||||||
<link rel="canonical" href="https://lukeattheroost.com">
|
<link rel="canonical" href="https://lukeattheroost.com">
|
||||||
|
|
||||||
<!-- OG / Social -->
|
<!-- OG / Social -->
|
||||||
<meta property="og:site_name" content="Luke at the Roost">
|
<meta property="og:site_name" content="Luke at the Roost">
|
||||||
<meta property="og:title" content="Luke at the Roost — AI Call-In Comedy Podcast">
|
<meta property="og:title" content="Luke at the Roost — AI Call-In Comedy Podcast">
|
||||||
<meta property="og:description" content="Late-night call-in radio from a desert hermit's RV. Real callers and AI characters talk to Luke about life, love, and everything in between.">
|
<meta property="og:description" content="AI-powered late-night call-in comedy podcast. Real callers and AI-generated characters talk to Luke about life, love, and everything in between. 37+ episodes.">
|
||||||
<meta property="og:image" content="https://cdn.lukeattheroost.com/media/podcasts/LukeAtTheRoost/cover_feed.png?v=3">
|
<meta property="og:image" content="https://cdn.lukeattheroost.com/media/podcasts/LukeAtTheRoost/cover_feed.png?v=3">
|
||||||
<meta property="og:url" content="https://lukeattheroost.com">
|
<meta property="og:url" content="https://lukeattheroost.com">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta name="twitter:card" content="summary_large_image">
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
<meta name="twitter:title" content="Luke at the Roost — AI Call-In Comedy Podcast">
|
<meta name="twitter:title" content="Luke at the Roost — AI Call-In Comedy Podcast">
|
||||||
<meta name="twitter:description" content="Late-night call-in radio from a desert hermit's RV. Real callers and AI characters talk to Luke about life, love, and everything in between.">
|
<meta name="twitter:description" content="AI-powered late-night call-in comedy podcast. Real callers and AI-generated characters talk to Luke about life, love, and everything in between. 37+ episodes.">
|
||||||
<meta name="twitter:image" content="https://cdn.lukeattheroost.com/media/podcasts/LukeAtTheRoost/cover_feed.png?v=3">
|
<meta name="twitter:image" content="https://cdn.lukeattheroost.com/media/podcasts/LukeAtTheRoost/cover_feed.png?v=3">
|
||||||
|
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
@@ -30,57 +31,97 @@
|
|||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
||||||
<link rel="stylesheet" href="css/style.css?v=2">
|
<link rel="stylesheet" href="css/style.css?v=6">
|
||||||
|
|
||||||
<!-- Structured Data -->
|
<!-- Structured Data -->
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{
|
[{
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "PodcastSeries",
|
"@type": "PodcastSeries",
|
||||||
"name": "Luke at the Roost",
|
"name": "Luke at the Roost",
|
||||||
"description": "The call-in talk show where Luke gives life advice to biologically questionable organisms. Broadcast from a desert hermit's RV, featuring a mix of real callers and AI-generated callers.",
|
"description": "An AI-powered late-night call-in comedy podcast. Real callers and AI-generated characters with unique personalities talk to host Luke MacNeil about life, love, relationships, and everything in between. Broadcast from a desert hermit's RV, featuring 37+ episodes of unpredictable conversations.",
|
||||||
"url": "https://lukeattheroost.com",
|
"url": "https://lukeattheroost.com",
|
||||||
"image": "https://cdn.lukeattheroost.com/media/podcasts/LukeAtTheRoost/cover_feed.png?v=3",
|
"image": "https://cdn.lukeattheroost.com/media/podcasts/LukeAtTheRoost/cover_feed.png?v=3",
|
||||||
"author": {
|
"author": {
|
||||||
"@type": "Person",
|
"@type": "Person",
|
||||||
"name": "Luke MacNeil"
|
"name": "Luke MacNeil",
|
||||||
|
"url": "https://lukeattheroost.com"
|
||||||
},
|
},
|
||||||
"publisher": {
|
"publisher": {
|
||||||
"@type": "Organization",
|
"@type": "Organization",
|
||||||
"name": "MacNeil Media Group"
|
"name": "MacNeil Media Group",
|
||||||
|
"url": "https://macneilmediagroup.com"
|
||||||
},
|
},
|
||||||
"genre": "Comedy",
|
"genre": ["Comedy", "Talk", "Technology"],
|
||||||
"inLanguage": "en",
|
"inLanguage": "en",
|
||||||
"webFeed": "https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml",
|
"webFeed": "https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml",
|
||||||
|
"startDate": "2026-02",
|
||||||
|
"keywords": "AI podcast, comedy, call-in radio, artificial intelligence, AI-generated callers, late-night talk show",
|
||||||
"sameAs": [
|
"sameAs": [
|
||||||
"https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF",
|
"https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF",
|
||||||
"https://podcasts.apple.com/us/podcast/luke-at-the-roost/id1875205848",
|
"https://podcasts.apple.com/us/podcast/luke-at-the-roost/id1875205848",
|
||||||
"https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-",
|
"https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-",
|
||||||
"https://discord.gg/5CnQZxDM"
|
"https://discord.gg/5CnQZxDM",
|
||||||
|
"https://www.instagram.com/lukeattheroost/",
|
||||||
|
"https://x.com/lukeattheroost",
|
||||||
|
"https://www.tiktok.com/@luke.at.the.roost",
|
||||||
|
"https://bsky.app/profile/lukeattheroost.bsky.social",
|
||||||
|
"https://www.facebook.com/profile.php?id=61588191627949",
|
||||||
|
"https://www.linkedin.com/company/luke-at-the-roost"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "WebSite",
|
||||||
|
"name": "Luke at the Roost",
|
||||||
|
"url": "https://lukeattheroost.com",
|
||||||
|
"description": "Official website for Luke at the Roost, an AI-powered late-night call-in comedy podcast.",
|
||||||
|
"publisher": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "MacNeil Media Group",
|
||||||
|
"url": "https://macneilmediagroup.com",
|
||||||
|
"logo": {
|
||||||
|
"@type": "ImageObject",
|
||||||
|
"url": "https://cdn.lukeattheroost.com/media/podcasts/LukeAtTheRoost/cover_feed.png?v=3"
|
||||||
|
},
|
||||||
|
"contactPoint": {
|
||||||
|
"@type": "ContactPoint",
|
||||||
|
"email": "luke@lukeattheroost.com",
|
||||||
|
"contactType": "customer support"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
</script>
|
</script>
|
||||||
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<a href="#main-content" class="skip-link">Skip to content</a>
|
||||||
|
|
||||||
|
<nav class="site-nav">
|
||||||
|
<a href="/" class="site-nav-brand">Luke at the Roost</a>
|
||||||
|
<div class="site-nav-links">
|
||||||
|
<a href="/how-it-works">How It Works</a>
|
||||||
|
<a href="/clips">Clips</a>
|
||||||
|
<a href="/stats">Stats</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main id="main-content">
|
||||||
|
|
||||||
<!-- Banner -->
|
<!-- Banner -->
|
||||||
<div class="banner">
|
<div class="banner">
|
||||||
<img src="images/banner.png" alt="Luke at the Roost — ON AIR" class="banner-img" width="1500" height="500">
|
<img src="images/banner.png" alt="Luke at the Roost — ON AIR" class="banner-img" width="1500" height="500" sizes="100vw" fetchpriority="high">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Hero -->
|
<!-- Hero -->
|
||||||
<section class="hero">
|
<section class="hero">
|
||||||
<div class="hero-inner">
|
<div class="hero-grid">
|
||||||
<img
|
<div class="hero-text">
|
||||||
class="cover-art"
|
<h1 class="sr-only">Luke at the Roost</h1>
|
||||||
src="images/cover.png"
|
<p class="tagline tagline--hero">Every caller is AI. Every conversation is real. Every episode is a disaster.</p>
|
||||||
alt="Luke at the Roost cover art"
|
<p class="tagline tagline--sub">The call-in talk show where Luke gives life advice to biologically questionable organisms.</p>
|
||||||
width="1440"
|
|
||||||
height="1440"
|
|
||||||
>
|
|
||||||
<div class="hero-info">
|
|
||||||
<h1>Luke at the Roost</h1>
|
|
||||||
<p class="tagline">The call-in talk show where Luke gives life advice to biologically questionable organisms.</p>
|
|
||||||
<div class="phone" id="phone-section">
|
<div class="phone" id="phone-section">
|
||||||
<div class="on-air-badge" id="on-air-badge">
|
<div class="on-air-badge" id="on-air-badge">
|
||||||
<span class="on-air-dot"></span>
|
<span class="on-air-dot"></span>
|
||||||
@@ -89,39 +130,67 @@
|
|||||||
<div class="off-air-badge" id="off-air-badge">
|
<div class="off-air-badge" id="off-air-badge">
|
||||||
OFF AIR
|
OFF AIR
|
||||||
</div>
|
</div>
|
||||||
<span class="phone-label">Call in live</span>
|
<span class="phone-inline">Call in: <strong>208-439-LUKE</strong></span>
|
||||||
<span class="phone-number">208-439-LUKE</span>
|
|
||||||
<span class="phone-digits">(208-439-5853)</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="subscribe-row">
|
<div class="subscribe-row">
|
||||||
<a href="https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF?si=f990713adce84ba4" target="_blank" rel="noopener" class="subscribe-btn btn-spotify">
|
<span class="subscribe-label">Listen On</span>
|
||||||
|
<div class="subscribe-buttons">
|
||||||
|
<a href="https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF?si=f990713adce84ba4" target="_blank" rel="noopener" class="subscribe-btn">
|
||||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z"/></svg>
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z"/></svg>
|
||||||
Spotify
|
Spotify
|
||||||
</a>
|
</a>
|
||||||
<a href="https://podcasts.apple.com/us/podcast/luke-at-the-roost/id1875205848" target="_blank" rel="noopener" class="subscribe-btn btn-apple">
|
<a href="https://podcasts.apple.com/us/podcast/luke-at-the-roost/id1875205848" target="_blank" rel="noopener" class="subscribe-btn">
|
||||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M5.34 0A5.328 5.328 0 0 0 0 5.34v13.32A5.328 5.328 0 0 0 5.34 24h13.32A5.328 5.328 0 0 0 24 18.66V5.34A5.328 5.328 0 0 0 18.66 0zm6.525 2.568c2.336 0 4.448.902 4.448 3.545 0 1.497-.89 2.67-1.916 3.545-.663.566-.795 .84-.795 1.347 0 .6.397 1.173.894 1.722 1.417 1.564 1.96 2.853 1.96 4.448 0 3.063-2.673 4.257-5.165 4.257-.315 0-.658-.02-.994-.063-1.523-.195-2.86-.9-3.632-.9-.82 0-1.98.623-3.377.87A5.715 5.715 0 0 1 3.15 21.4c-1.27 0-2.1-.96-2.1-2.663 0-1.2.6-2.7 1.845-4.29.63-.81 1.62-1.83 2.91-2.31-.06-.6-.09-1.14-.09-1.62 0-4.28 2.76-7.95 6.15-7.95z"/></svg>
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M5.34 0A5.328 5.328 0 0 0 0 5.34v13.32A5.328 5.328 0 0 0 5.34 24h13.32A5.328 5.328 0 0 0 24 18.66V5.34A5.328 5.328 0 0 0 18.66 0zm6.525 2.568c2.336 0 4.448.902 4.448 3.545 0 1.497-.89 2.67-1.916 3.545-.663.566-.795 .84-.795 1.347 0 .6.397 1.173.894 1.722 1.417 1.564 1.96 2.853 1.96 4.448 0 3.063-2.673 4.257-5.165 4.257-.315 0-.658-.02-.994-.063-1.523-.195-2.86-.9-3.632-.9-.82 0-1.98.623-3.377.87A5.715 5.715 0 0 1 3.15 21.4c-1.27 0-2.1-.96-2.1-2.663 0-1.2.6-2.7 1.845-4.29.63-.81 1.62-1.83 2.91-2.31-.06-.6-.09-1.14-.09-1.62 0-4.28 2.76-7.95 6.15-7.95z"/></svg>
|
||||||
Apple
|
Apple
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-" target="_blank" rel="noopener" class="subscribe-btn btn-youtube">
|
<a href="https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-" target="_blank" rel="noopener" class="subscribe-btn">
|
||||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg>
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg>
|
||||||
YouTube
|
YouTube
|
||||||
</a>
|
</a>
|
||||||
</div>
|
<a href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml" target="_blank" rel="noopener" class="subscribe-btn">
|
||||||
<div class="secondary-links">
|
|
||||||
<a href="/how-it-works" class="secondary-link">
|
|
||||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/></svg>
|
|
||||||
How It Works
|
|
||||||
</a>
|
|
||||||
<a href="https://discord.gg/5CnQZxDM" target="_blank" rel="noopener" class="secondary-link">
|
|
||||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.947 2.418-2.157 2.418z"/></svg>
|
|
||||||
Discord
|
|
||||||
</a>
|
|
||||||
<a href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml" target="_blank" rel="noopener" class="secondary-link">
|
|
||||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M6.503 20.752c0 1.794-1.456 3.248-3.251 3.248S0 22.546 0 20.752s1.456-3.248 3.252-3.248 3.251 1.454 3.251 3.248zM.002 9.473v4.594c5.508.163 9.929 4.584 10.092 10.091h4.594C14.524 16.21 7.849 9.636.002 9.473zM.006 0v4.604C10.81 4.77 19.23 13.19 19.396 24h4.604C23.834 10.952 13.054.166.006 0z"/></svg>
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M6.503 20.752c0 1.794-1.456 3.248-3.251 3.248S0 22.546 0 20.752s1.456-3.248 3.252-3.248 3.251 1.454 3.251 3.248zM.002 9.473v4.594c5.508.163 9.929 4.584 10.092 10.091h4.594C14.524 16.21 7.849 9.636.002 9.473zM.006 0v4.604C10.81 4.77 19.23 13.19 19.396 24h4.604C23.834 10.952 13.054.166.006 0z"/></svg>
|
||||||
RSS
|
RSS
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="hero-links">
|
||||||
|
<a href="/how-it-works">How It Works</a>
|
||||||
|
<span class="hero-links-sep">·</span>
|
||||||
|
<a href="https://ko-fi.com/lukemacneil" target="_blank" rel="noopener" class="support-link">Support the Show</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Social Proof Strip -->
|
||||||
|
<section class="proof-strip">
|
||||||
|
<div class="proof-strip-inner">
|
||||||
|
<blockquote class="proof-quote">"I've been Diane for seven months and I can't stop."<cite>— Not Diane, Ep. 24</cite></blockquote>
|
||||||
|
<blockquote class="proof-quote">"I tasted the exit sign. Like green metal in my mouth."<cite>— Floyd, Ep. 15</cite></blockquote>
|
||||||
|
<blockquote class="proof-quote">"I'm holding his dogs until he pays up. All three of them."<cite>— Mavis, Ep. 24</cite></blockquote>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Best Clips -->
|
||||||
|
<section class="home-clips-section">
|
||||||
|
<div class="home-clips-header">
|
||||||
|
<h2>Best Clips</h2>
|
||||||
|
<a href="/clips" class="clips-see-all">See all clips →</a>
|
||||||
|
</div>
|
||||||
|
<div class="home-clips-grid" id="home-clips"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Featured Episode -->
|
||||||
|
<section class="featured-episode-section">
|
||||||
|
<h2>Latest Episode</h2>
|
||||||
|
<div id="featured-episode"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Episodes -->
|
||||||
|
<section class="episodes-section">
|
||||||
|
<h2 id="episodes-heading">Episodes</h2>
|
||||||
|
<div class="episodes-list" id="episodes-list">
|
||||||
|
<div class="episodes-loading">Loading episodes...</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -199,39 +268,17 @@
|
|||||||
<div class="testimonials-dots" id="testimonials-dots"></div>
|
<div class="testimonials-dots" id="testimonials-dots"></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Episodes -->
|
</main>
|
||||||
<section class="episodes-section">
|
|
||||||
<h2>Episodes</h2>
|
|
||||||
<div class="episodes-list" id="episodes-list">
|
|
||||||
<div class="episodes-loading">Loading episodes...</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- Footer -->
|
<footer class="footer"></footer>
|
||||||
<footer class="footer">
|
|
||||||
<div class="footer-links">
|
<!-- Sticky CTA Bar — appears after scrolling past hero -->
|
||||||
<a href="/how-it-works">How It Works</a>
|
<div class="sticky-cta" id="sticky-cta" aria-hidden="true">
|
||||||
<a href="/stats">Stats</a>
|
<a href="tel:+12084395853" class="sticky-cta-link">
|
||||||
<a href="https://discord.gg/5CnQZxDM" target="_blank" rel="noopener">Discord</a>
|
<svg class="sticky-cta-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></svg>
|
||||||
<a href="https://www.facebook.com/profile.php?id=61588191627949" target="_blank" rel="noopener">Facebook</a>
|
Call in live: <strong>208-439-LUKE</strong>
|
||||||
<a href="https://x.com/lukeattheroost" target="_blank" rel="noopener">X</a>
|
</a>
|
||||||
<a href="https://bsky.app/profile/lukeattheroost.bsky.social" target="_blank" rel="noopener">Bluesky</a>
|
|
||||||
<a href="https://mastodon.macneilmediagroup.com/@lukeattheroost" target="_blank" rel="me noopener">Mastodon</a>
|
|
||||||
<a href="https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF?si=f990713adce84ba4" target="_blank" rel="noopener">Spotify</a>
|
|
||||||
<a href="https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-" target="_blank" rel="noopener">YouTube</a>
|
|
||||||
<a href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml" target="_blank" rel="noopener">RSS</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-projects">
|
|
||||||
<span class="footer-projects-label">More from Luke</span>
|
|
||||||
<div class="footer-projects-links">
|
|
||||||
<a href="https://macneilmediagroup.com" target="_blank" rel="noopener">MacNeil Media Group</a>
|
|
||||||
<a href="https://prints.macneilmediagroup.com" target="_blank" rel="noopener">Photography Prints</a>
|
|
||||||
<a href="https://youtube.com/lukemacneil" target="_blank" rel="noopener">YouTube</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="footer-contact">Sales & Collaboration: <a href="mailto:luke@macneilmediagroup.com">luke@macneilmediagroup.com</a></p>
|
|
||||||
<p>© 2026 Luke at the Roost · <a href="/privacy">Privacy Policy</a></p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<!-- Sticky Audio Player -->
|
<!-- Sticky Audio Player -->
|
||||||
<div class="sticky-player" id="sticky-player">
|
<div class="sticky-player" id="sticky-player">
|
||||||
@@ -243,7 +290,7 @@
|
|||||||
<div class="player-info">
|
<div class="player-info">
|
||||||
<div class="player-title" id="player-title">—</div>
|
<div class="player-title" id="player-title">—</div>
|
||||||
<div class="player-progress-row">
|
<div class="player-progress-row">
|
||||||
<div class="player-progress" id="player-progress">
|
<div class="player-progress" id="player-progress" role="slider" aria-label="Audio progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" tabindex="0">
|
||||||
<div class="player-progress-fill" id="player-progress-fill"></div>
|
<div class="player-progress-fill" id="player-progress-fill"></div>
|
||||||
</div>
|
</div>
|
||||||
<span class="player-time" id="player-time">0:00 / 0:00</span>
|
<span class="player-time" id="player-time">0:00 / 0:00</span>
|
||||||
@@ -254,6 +301,10 @@
|
|||||||
|
|
||||||
<audio id="audio-element" preload="none"></audio>
|
<audio id="audio-element" preload="none"></audio>
|
||||||
|
|
||||||
<script src="js/app.js?v=2"></script>
|
<script src="js/footer.js"></script>
|
||||||
|
<script src="js/clips.js"></script>
|
||||||
|
<script>renderFeaturedClipsInline('home-clips');</script>
|
||||||
|
<script src="js/player.js"></script>
|
||||||
|
<script src="js/app.js?v=6"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,25 +1,14 @@
|
|||||||
const FEED_URL = '/feed';
|
const FEED_URL = '/feed';
|
||||||
|
const EPISODES_PER_PAGE = 10;
|
||||||
|
|
||||||
const audio = document.getElementById('audio-element');
|
|
||||||
const stickyPlayer = document.getElementById('sticky-player');
|
|
||||||
const playerPlayBtn = document.getElementById('player-play-btn');
|
|
||||||
const playerTitle = document.getElementById('player-title');
|
|
||||||
const playerProgress = document.getElementById('player-progress');
|
|
||||||
const playerProgressFill = document.getElementById('player-progress-fill');
|
|
||||||
const playerTime = document.getElementById('player-time');
|
|
||||||
const episodesList = document.getElementById('episodes-list');
|
const episodesList = document.getElementById('episodes-list');
|
||||||
|
|
||||||
let currentEpisodeCard = null;
|
let currentEpisodeCard = null;
|
||||||
|
let allEpisodes = [];
|
||||||
|
let displayedCount = 0;
|
||||||
|
|
||||||
// Format seconds to M:SS or H:MM:SS
|
function escapeAttr(str) {
|
||||||
function formatTime(seconds) {
|
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
||||||
if (!seconds || isNaN(seconds)) return '0:00';
|
|
||||||
const s = Math.floor(seconds);
|
|
||||||
const h = Math.floor(s / 3600);
|
|
||||||
const m = Math.floor((s % 3600) / 60);
|
|
||||||
const sec = s % 60;
|
|
||||||
if (h > 0) return `${h}:${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`;
|
|
||||||
return `${m}:${String(sec).padStart(2, '0')}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format duration from itunes:duration (could be seconds or HH:MM:SS)
|
// Format duration from itunes:duration (could be seconds or HH:MM:SS)
|
||||||
@@ -43,18 +32,32 @@ function formatDate(dateStr) {
|
|||||||
return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip HTML tags and truncate
|
function stripHtml(html) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.innerHTML = html || '';
|
||||||
|
return div.textContent || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip HTML tags and truncate at word boundary (returns escaped text safe for innerHTML)
|
||||||
function truncate(html, maxLen) {
|
function truncate(html, maxLen) {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.innerHTML = html || '';
|
div.innerHTML = html || '';
|
||||||
const text = div.textContent || '';
|
const text = div.textContent || '';
|
||||||
if (text.length <= maxLen) return text;
|
let result;
|
||||||
return text.slice(0, maxLen).trimEnd() + '...';
|
if (text.length <= maxLen) {
|
||||||
|
result = text;
|
||||||
|
} else {
|
||||||
|
const truncated = text.slice(0, maxLen);
|
||||||
|
const lastSpace = truncated.lastIndexOf(' ');
|
||||||
|
result = (lastSpace > maxLen * 0.5 ? truncated.slice(0, lastSpace) : truncated).trimEnd() + '...';
|
||||||
|
}
|
||||||
|
return escapeAttr(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SVG icons
|
// SVG icons
|
||||||
const playSVG = '<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>';
|
const playSVG = '<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>';
|
||||||
const pauseSVG = '<svg viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';
|
const pauseSVG = '<svg viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';
|
||||||
|
const shareSVG = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M16 5l-1.42 1.42-1.59-1.59V16h-2V4.83L9.42 6.42 8 5l4-4 4 4zm4 5v11a2 2 0 01-2 2H6a2 2 0 01-2-2V10a2 2 0 012-2h3v2H6v11h12V10h-3V8h3a2 2 0 012 2z"/></svg>';
|
||||||
|
|
||||||
// Fetch with timeout
|
// Fetch with timeout
|
||||||
function fetchWithTimeout(url, ms = 8000) {
|
function fetchWithTimeout(url, ms = 8000) {
|
||||||
@@ -63,6 +66,64 @@ function fetchWithTimeout(url, ms = 8000) {
|
|||||||
return fetch(url, { signal: controller.signal }).finally(() => clearTimeout(timeout));
|
return fetch(url, { signal: controller.signal }).finally(() => clearTimeout(timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function shareContent(title, url, btn) {
|
||||||
|
if (navigator.share) {
|
||||||
|
try {
|
||||||
|
await navigator.share({ title, url });
|
||||||
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name === 'AbortError') return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(url);
|
||||||
|
const orig = btn.innerHTML;
|
||||||
|
btn.innerHTML = 'Copied!';
|
||||||
|
btn.classList.add('share-copied');
|
||||||
|
setTimeout(() => { btn.innerHTML = orig; btn.classList.remove('share-copied'); }, 2000);
|
||||||
|
} catch (e) {
|
||||||
|
prompt('Copy this link:', url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFeaturedCard(ep) {
|
||||||
|
const card = document.createElement('div');
|
||||||
|
card.className = 'featured-episode-card';
|
||||||
|
|
||||||
|
const epLabel = ep.episodeNum ? `Episode ${ep.episodeNum}` : '';
|
||||||
|
const dateStr = ep.pubDate ? formatDate(ep.pubDate) : '';
|
||||||
|
const durStr = parseDuration(ep.duration);
|
||||||
|
const metaParts = [epLabel, dateStr, durStr].filter(Boolean).join(' · ');
|
||||||
|
const epSlug = ep.link ? ep.link.split('/episodes/').pop()?.replace(/\/$/, '') : '';
|
||||||
|
const fullDesc = escapeAttr(stripHtml(ep.description));
|
||||||
|
|
||||||
|
card.innerHTML = `
|
||||||
|
<div class="featured-episode-meta">
|
||||||
|
<span class="episode-new-badge">NEW</span> ${metaParts}
|
||||||
|
</div>
|
||||||
|
<div class="featured-episode-title">${escapeAttr(ep.title)}</div>
|
||||||
|
<div class="featured-episode-desc">${fullDesc}</div>
|
||||||
|
<div class="featured-episode-actions">
|
||||||
|
<button class="episode-play-btn featured-play-btn" aria-label="Play ${escapeAttr(ep.title)}">
|
||||||
|
${playSVG}
|
||||||
|
</button>
|
||||||
|
${epSlug ? `<a href="/episode.html?slug=${encodeURIComponent(epSlug)}" class="episode-transcript-link">Read Transcript</a>` : ''}
|
||||||
|
<button class="episode-share-btn" aria-label="Share episode">${shareSVG}</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const playBtn = card.querySelector('.featured-play-btn');
|
||||||
|
playBtn.addEventListener('click', () => playEpisode(ep.audioUrl, ep.title, card, playBtn));
|
||||||
|
|
||||||
|
const shareBtn = card.querySelector('.episode-share-btn');
|
||||||
|
const shareUrl = epSlug
|
||||||
|
? `${window.location.origin}/episode.html?slug=${encodeURIComponent(epSlug)}`
|
||||||
|
: window.location.origin;
|
||||||
|
shareBtn.addEventListener('click', () => shareContent(ep.title, shareUrl, shareBtn));
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch and parse RSS feed
|
// Fetch and parse RSS feed
|
||||||
async function fetchEpisodes() {
|
async function fetchEpisodes() {
|
||||||
let xml;
|
let xml;
|
||||||
@@ -91,7 +152,7 @@ async function fetchEpisodes() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const episodes = Array.from(items).map((item, i) => {
|
const episodes = Array.from(items).map((item) => {
|
||||||
const title = item.querySelector('title')?.textContent || 'Untitled';
|
const title = item.querySelector('title')?.textContent || 'Untitled';
|
||||||
const description = item.querySelector('description')?.textContent || '';
|
const description = item.querySelector('description')?.textContent || '';
|
||||||
const enclosure = item.querySelector('enclosure');
|
const enclosure = item.querySelector('enclosure');
|
||||||
@@ -108,9 +169,26 @@ async function fetchEpisodes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderEpisodes(episodes) {
|
function renderEpisodes(episodes) {
|
||||||
episodesList.innerHTML = '';
|
// Featured episode — render newest into dedicated container
|
||||||
|
const featuredContainer = document.getElementById('featured-episode');
|
||||||
|
if (featuredContainer && episodes.length > 0) {
|
||||||
|
featuredContainer.innerHTML = '';
|
||||||
|
featuredContainer.appendChild(createFeaturedCard(episodes[0]));
|
||||||
|
allEpisodes = episodes.slice(1);
|
||||||
|
} else {
|
||||||
|
allEpisodes = episodes;
|
||||||
|
}
|
||||||
|
|
||||||
episodes.forEach((ep) => {
|
// Update heading with total episode count
|
||||||
|
const heading = document.getElementById('episodes-heading');
|
||||||
|
if (heading) heading.textContent = `All Episodes (${episodes.length})`;
|
||||||
|
|
||||||
|
displayedCount = 0;
|
||||||
|
episodesList.innerHTML = '';
|
||||||
|
showMoreEpisodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEpisodeCard(ep) {
|
||||||
const card = document.createElement('div');
|
const card = document.createElement('div');
|
||||||
card.className = 'episode-card';
|
card.className = 'episode-card';
|
||||||
|
|
||||||
@@ -122,28 +200,53 @@ function renderEpisodes(episodes) {
|
|||||||
const epSlug = ep.link ? ep.link.split('/episodes/').pop()?.replace(/\/$/, '') : '';
|
const epSlug = ep.link ? ep.link.split('/episodes/').pop()?.replace(/\/$/, '') : '';
|
||||||
|
|
||||||
card.innerHTML = `
|
card.innerHTML = `
|
||||||
<button class="episode-play-btn" aria-label="Play ${ep.title}" data-url="${ep.audioUrl}" data-title="${ep.title.replace(/"/g, '"')}">
|
<button class="episode-play-btn" aria-label="Play ${escapeAttr(ep.title)}" data-url="${escapeAttr(ep.audioUrl)}" data-title="${escapeAttr(ep.title)}">
|
||||||
${playSVG}
|
${playSVG}
|
||||||
</button>
|
</button>
|
||||||
<div class="episode-info">
|
<div class="episode-info">
|
||||||
<div class="episode-meta">${metaParts}</div>
|
<div class="episode-meta">${metaParts}</div>
|
||||||
<div class="episode-title">${ep.title}</div>
|
<div class="episode-title">${escapeAttr(ep.title)}</div>
|
||||||
<div class="episode-desc">${truncate(ep.description, 150)}</div>
|
<div class="episode-desc">${truncate(ep.description, 150)}</div>
|
||||||
${epSlug ? `<a href="/episode.html?slug=${epSlug}" class="episode-transcript-link">Read Transcript</a>` : ''}
|
${epSlug ? `<a href="/episode.html?slug=${encodeURIComponent(epSlug)}" class="episode-transcript-link">Read Transcript</a>` : ''}
|
||||||
|
<button class="episode-share-btn" aria-label="Share episode">${shareSVG}</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const btn = card.querySelector('.episode-play-btn');
|
const btn = card.querySelector('.episode-play-btn');
|
||||||
btn.addEventListener('click', () => playEpisode(ep.audioUrl, ep.title, card, btn));
|
btn.addEventListener('click', () => playEpisode(ep.audioUrl, ep.title, card, btn));
|
||||||
|
|
||||||
episodesList.appendChild(card);
|
const shareBtn = card.querySelector('.episode-share-btn');
|
||||||
|
const shareUrl = epSlug
|
||||||
|
? `${window.location.origin}/episode.html?slug=${encodeURIComponent(epSlug)}`
|
||||||
|
: window.location.origin;
|
||||||
|
shareBtn.addEventListener('click', () => shareContent(ep.title, shareUrl, shareBtn));
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMoreEpisodes() {
|
||||||
|
const batch = allEpisodes.slice(displayedCount, displayedCount + EPISODES_PER_PAGE);
|
||||||
|
batch.forEach((ep) => {
|
||||||
|
episodesList.appendChild(createEpisodeCard(ep));
|
||||||
});
|
});
|
||||||
|
displayedCount += batch.length;
|
||||||
|
|
||||||
|
const existing = document.getElementById('load-more-btn');
|
||||||
|
if (existing) existing.remove();
|
||||||
|
|
||||||
|
if (displayedCount < allEpisodes.length) {
|
||||||
|
const btn = document.createElement('button');
|
||||||
|
btn.id = 'load-more-btn';
|
||||||
|
btn.className = 'load-more-btn';
|
||||||
|
btn.textContent = `Load More (${allEpisodes.length - displayedCount} remaining)`;
|
||||||
|
btn.addEventListener('click', showMoreEpisodes);
|
||||||
|
episodesList.after(btn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function playEpisode(url, title, card, btn) {
|
function playEpisode(url, title, card, btn) {
|
||||||
if (!url) return;
|
if (!url) return;
|
||||||
|
|
||||||
// If clicking the same episode that's playing, toggle play/pause
|
|
||||||
if (audio.src === url || audio.src === encodeURI(url)) {
|
if (audio.src === url || audio.src === encodeURI(url)) {
|
||||||
if (audio.paused) {
|
if (audio.paused) {
|
||||||
audio.play();
|
audio.play();
|
||||||
@@ -153,7 +256,6 @@ function playEpisode(url, title, card, btn) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset previous card button icon
|
|
||||||
if (currentEpisodeCard) {
|
if (currentEpisodeCard) {
|
||||||
const prevBtn = currentEpisodeCard.querySelector('.episode-play-btn');
|
const prevBtn = currentEpisodeCard.querySelector('.episode-play-btn');
|
||||||
if (prevBtn) {
|
if (prevBtn) {
|
||||||
@@ -168,37 +270,11 @@ function playEpisode(url, title, card, btn) {
|
|||||||
|
|
||||||
playerTitle.textContent = title;
|
playerTitle.textContent = title;
|
||||||
stickyPlayer.classList.add('active');
|
stickyPlayer.classList.add('active');
|
||||||
|
if (stickyCta) stickyCta.classList.add('player-active');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync UI with audio state
|
// Episode card icon sync (sticky player icons handled by player.js)
|
||||||
audio.addEventListener('play', () => {
|
function updateCardIcon(playing) {
|
||||||
updatePlayIcons(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
audio.addEventListener('pause', () => {
|
|
||||||
updatePlayIcons(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
audio.addEventListener('timeupdate', () => {
|
|
||||||
if (audio.duration) {
|
|
||||||
const pct = (audio.currentTime / audio.duration) * 100;
|
|
||||||
playerProgressFill.style.width = pct + '%';
|
|
||||||
playerTime.textContent = `${formatTime(audio.currentTime)} / ${formatTime(audio.duration)}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
audio.addEventListener('ended', () => {
|
|
||||||
updatePlayIcons(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
function updatePlayIcons(playing) {
|
|
||||||
// Sticky player icons
|
|
||||||
const iconPlay = playerPlayBtn.querySelector('.icon-play');
|
|
||||||
const iconPause = playerPlayBtn.querySelector('.icon-pause');
|
|
||||||
if (iconPlay) iconPlay.style.display = playing ? 'none' : 'block';
|
|
||||||
if (iconPause) iconPause.style.display = playing ? 'block' : 'none';
|
|
||||||
|
|
||||||
// Episode card icon
|
|
||||||
if (currentEpisodeCard) {
|
if (currentEpisodeCard) {
|
||||||
const btn = currentEpisodeCard.querySelector('.episode-play-btn');
|
const btn = currentEpisodeCard.querySelector('.episode-play-btn');
|
||||||
if (btn) {
|
if (btn) {
|
||||||
@@ -208,22 +284,9 @@ function updatePlayIcons(playing) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sticky player play/pause button
|
audio.addEventListener('play', () => updateCardIcon(true));
|
||||||
playerPlayBtn.addEventListener('click', () => {
|
audio.addEventListener('pause', () => updateCardIcon(false));
|
||||||
if (audio.src) {
|
audio.addEventListener('ended', () => updateCardIcon(false));
|
||||||
if (audio.paused) audio.play();
|
|
||||||
else audio.pause();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Progress bar seeking
|
|
||||||
playerProgress.addEventListener('click', (e) => {
|
|
||||||
if (audio.duration) {
|
|
||||||
const rect = playerProgress.getBoundingClientRect();
|
|
||||||
const pct = (e.clientX - rect.left) / rect.width;
|
|
||||||
audio.currentTime = pct * audio.duration;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Testimonials Slider
|
// Testimonials Slider
|
||||||
function initTestimonials() {
|
function initTestimonials() {
|
||||||
@@ -318,6 +381,18 @@ function checkOnAir() {
|
|||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sticky CTA — show after scrolling past hero
|
||||||
|
const stickyCta = document.getElementById('sticky-cta');
|
||||||
|
const heroSection = document.querySelector('.hero');
|
||||||
|
if (stickyCta && heroSection) {
|
||||||
|
const ctaObserver = new IntersectionObserver(([entry]) => {
|
||||||
|
const show = !entry.isIntersecting;
|
||||||
|
stickyCta.classList.toggle('visible', show);
|
||||||
|
stickyCta.setAttribute('aria-hidden', String(!show));
|
||||||
|
}, { threshold: 0 });
|
||||||
|
ctaObserver.observe(heroSection);
|
||||||
|
}
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
fetchEpisodes();
|
fetchEpisodes();
|
||||||
initTestimonials();
|
initTestimonials();
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
const CLIPS_JSON_URL = '/data/clips.json';
|
||||||
|
|
||||||
|
const clipPlaySVG = '<svg viewBox="0 0 24 24" fill="#fff"><path d="M8 5v14l11-7z"/></svg>';
|
||||||
|
const clipShareSVG = '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M16 5l-1.42 1.42-1.59-1.59V16h-2V4.83L9.42 6.42 8 5l4-4 4 4zm4 5v11a2 2 0 01-2 2H6a2 2 0 01-2-2V10a2 2 0 012-2h3v2H6v11h12V10h-3V8h3a2 2 0 012 2z"/></svg>';
|
||||||
|
|
||||||
|
function escapeHTML(str) {
|
||||||
|
const el = document.createElement('span');
|
||||||
|
el.textContent = str;
|
||||||
|
return el.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function shareClipContent(title, url, btn) {
|
||||||
|
if (navigator.share) {
|
||||||
|
try {
|
||||||
|
await navigator.share({ title, url });
|
||||||
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name === 'AbortError') return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(url);
|
||||||
|
const orig = btn.innerHTML;
|
||||||
|
btn.innerHTML = 'Copied!';
|
||||||
|
btn.classList.add('share-copied');
|
||||||
|
setTimeout(() => { btn.innerHTML = orig; btn.classList.remove('share-copied'); }, 2000);
|
||||||
|
} catch (e) {
|
||||||
|
prompt('Copy this link:', url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderClipCard(clip, featured) {
|
||||||
|
const card = document.createElement('div');
|
||||||
|
card.className = 'clip-card' + (featured ? ' clip-card-featured' : '');
|
||||||
|
|
||||||
|
const youtubeId = (clip.youtube_id || '').replace(/[^a-zA-Z0-9_-]/g, '');
|
||||||
|
if (youtubeId) card.dataset.youtubeId = youtubeId;
|
||||||
|
const hasVideo = !!youtubeId;
|
||||||
|
const epLabel = clip.episode_number ? `Episode ${Number(clip.episode_number)}` : '';
|
||||||
|
const title = escapeHTML(clip.title || '');
|
||||||
|
const desc = escapeHTML(clip.description || '');
|
||||||
|
|
||||||
|
const thumbImg = clip.thumbnail && /^[\w\/.-]+$/.test(clip.thumbnail)
|
||||||
|
? `<img class="clip-card-thumb" src="/${clip.thumbnail}" alt="${title}" loading="lazy">`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
card.innerHTML = `
|
||||||
|
<div class="clip-card-inner">
|
||||||
|
${thumbImg}
|
||||||
|
<div class="clip-card-overlay">
|
||||||
|
<span class="clip-episode-label">${epLabel}</span>
|
||||||
|
<h3 class="clip-card-title">${title}</h3>
|
||||||
|
<p class="clip-card-desc">${desc}</p>
|
||||||
|
${hasVideo ? `<button class="clip-play-btn" aria-label="Play clip">${clipPlaySVG}</button>` : ''}
|
||||||
|
${hasVideo ? `<button class="clip-share-btn" aria-label="Share clip">${clipShareSVG}</button>` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
if (hasVideo) {
|
||||||
|
card.querySelector('.clip-play-btn').addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const inner = card.querySelector('.clip-card-inner');
|
||||||
|
inner.innerHTML = `<iframe src="https://www.youtube-nocookie.com/embed/${youtubeId}?autoplay=1&rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>`;
|
||||||
|
});
|
||||||
|
const shareBtn = card.querySelector('.clip-share-btn');
|
||||||
|
if (shareBtn) {
|
||||||
|
shareBtn.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
shareClipContent(clip.title || '', `https://youtube.com/watch?v=${youtubeId}`, shareBtn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchClips() {
|
||||||
|
try {
|
||||||
|
const res = await fetch(CLIPS_JSON_URL);
|
||||||
|
if (!res.ok) throw new Error('Failed to fetch clips');
|
||||||
|
return await res.json();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error loading clips:', err);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initClipsPage() {
|
||||||
|
const clips = await fetchClips();
|
||||||
|
if (!clips.length) return;
|
||||||
|
|
||||||
|
const featuredContainer = document.querySelector('.clips-featured');
|
||||||
|
const gridContainer = document.querySelector('.clips-grid');
|
||||||
|
|
||||||
|
if (featuredContainer) {
|
||||||
|
clips.filter(c => c.featured).forEach(clip => {
|
||||||
|
featuredContainer.appendChild(renderClipCard(clip, true));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gridContainer) {
|
||||||
|
clips.filter(c => !c.featured).forEach(clip => {
|
||||||
|
gridContainer.appendChild(renderClipCard(clip, false));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function renderFeaturedClipsInline(containerId) {
|
||||||
|
const container = document.getElementById(containerId);
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
const clips = await fetchClips();
|
||||||
|
const featured = clips.filter(c => c.featured);
|
||||||
|
|
||||||
|
featured.forEach(clip => {
|
||||||
|
container.appendChild(renderClipCard(clip, true));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-init if clips page containers exist
|
||||||
|
if (document.querySelector('.clips-featured') || document.querySelector('.clips-grid')) {
|
||||||
|
initClipsPage();
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
const FEED_URL = '/feed';
|
||||||
|
|
||||||
|
function formatDate(dateStr) {
|
||||||
|
return new Date(dateStr).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseDuration(raw) {
|
||||||
|
if (!raw) return '';
|
||||||
|
if (raw.includes(':')) {
|
||||||
|
const parts = raw.split(':').map(Number);
|
||||||
|
let t = 0;
|
||||||
|
if (parts.length === 3) t = parts[0]*3600 + parts[1]*60 + parts[2];
|
||||||
|
else if (parts.length === 2) t = parts[0]*60 + parts[1];
|
||||||
|
return `${Math.round(t/60)} min`;
|
||||||
|
}
|
||||||
|
const sec = parseInt(raw, 10);
|
||||||
|
return isNaN(sec) ? '' : `${Math.round(sec/60)} min`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stripHtml(html) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.innerHTML = html || '';
|
||||||
|
return div.textContent || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(str) {
|
||||||
|
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get slug from URL
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const slug = params.get('slug');
|
||||||
|
|
||||||
|
if (!slug) {
|
||||||
|
document.getElementById('ep-title').textContent = 'Episode not found';
|
||||||
|
document.getElementById('transcript-body').innerHTML = '<p>No episode specified. <a href="/">Go back to episodes.</a></p>';
|
||||||
|
} else {
|
||||||
|
loadEpisode(slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadEpisode(slug) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(FEED_URL);
|
||||||
|
const xml = await res.text();
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const doc = parser.parseFromString(xml, 'text/xml');
|
||||||
|
const items = doc.querySelectorAll('item');
|
||||||
|
|
||||||
|
let episode = null;
|
||||||
|
for (const item of items) {
|
||||||
|
const link = item.querySelector('link')?.textContent || '';
|
||||||
|
const itemSlug = link.split('/episodes/').pop()?.replace(/\/$/, '');
|
||||||
|
if (itemSlug === slug) {
|
||||||
|
episode = {
|
||||||
|
title: item.querySelector('title')?.textContent || 'Untitled',
|
||||||
|
description: item.querySelector('description')?.textContent || '',
|
||||||
|
audioUrl: item.querySelector('enclosure')?.getAttribute('url') || '',
|
||||||
|
pubDate: item.querySelector('pubDate')?.textContent || '',
|
||||||
|
duration: item.getElementsByTagNameNS('http://www.itunes.com/dtds/podcast-1.0.dtd', 'duration')[0]?.textContent || '',
|
||||||
|
episodeNum: item.getElementsByTagNameNS('http://www.itunes.com/dtds/podcast-1.0.dtd', 'episode')[0]?.textContent || '',
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!episode) {
|
||||||
|
document.getElementById('ep-title').textContent = 'Episode not found';
|
||||||
|
document.getElementById('transcript-body').innerHTML = '<p>Could not find this episode. <a href="/">Go back to episodes.</a></p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate header
|
||||||
|
const metaParts = [
|
||||||
|
episode.episodeNum ? `Episode ${episode.episodeNum}` : '',
|
||||||
|
episode.pubDate ? formatDate(episode.pubDate) : '',
|
||||||
|
parseDuration(episode.duration),
|
||||||
|
].filter(Boolean).join(' \u00b7 ');
|
||||||
|
|
||||||
|
document.getElementById('ep-meta').textContent = metaParts;
|
||||||
|
document.getElementById('ep-title').textContent = episode.title;
|
||||||
|
document.getElementById('ep-desc').textContent = stripHtml(episode.description || '');
|
||||||
|
|
||||||
|
// Update page meta
|
||||||
|
document.title = `${episode.title} — Luke at the Roost`;
|
||||||
|
document.getElementById('page-description')?.setAttribute('content', `Full transcript of ${episode.title} from Luke at the Roost.`);
|
||||||
|
document.getElementById('og-title')?.setAttribute('content', episode.title);
|
||||||
|
document.getElementById('og-description')?.setAttribute('content', stripHtml(episode.description).slice(0, 200));
|
||||||
|
const canonicalUrl = `https://lukeattheroost.com/episode.html?slug=${slug}`;
|
||||||
|
document.getElementById('page-canonical')?.setAttribute('href', canonicalUrl);
|
||||||
|
document.getElementById('og-url')?.setAttribute('content', canonicalUrl);
|
||||||
|
document.getElementById('tw-title')?.setAttribute('content', episode.title);
|
||||||
|
document.getElementById('tw-description')?.setAttribute('content', stripHtml(episode.description).slice(0, 200));
|
||||||
|
|
||||||
|
// Update JSON-LD structured data
|
||||||
|
const jsonLd = document.getElementById('episode-jsonld');
|
||||||
|
if (jsonLd) {
|
||||||
|
const ld = JSON.parse(jsonLd.textContent);
|
||||||
|
ld.name = episode.title;
|
||||||
|
ld.url = canonicalUrl;
|
||||||
|
ld.description = stripHtml(episode.description).slice(0, 300);
|
||||||
|
if (episode.pubDate) ld.datePublished = new Date(episode.pubDate).toISOString().split('T')[0];
|
||||||
|
if (episode.episodeNum) ld.episodeNumber = parseInt(episode.episodeNum, 10);
|
||||||
|
if (episode.audioUrl) {
|
||||||
|
ld.associatedMedia = {
|
||||||
|
"@type": "MediaObject",
|
||||||
|
"contentUrl": episode.audioUrl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
jsonLd.textContent = JSON.stringify(ld);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play button
|
||||||
|
if (episode.audioUrl) {
|
||||||
|
const playBtn = document.getElementById('ep-play-btn');
|
||||||
|
playBtn.style.display = 'inline-flex';
|
||||||
|
playBtn.addEventListener('click', () => {
|
||||||
|
audio.src = episode.audioUrl;
|
||||||
|
audio.play();
|
||||||
|
playerTitle.textContent = episode.title;
|
||||||
|
stickyPlayer.classList.add('active');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
document.getElementById('ep-title').textContent = 'Error loading episode';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch transcript
|
||||||
|
try {
|
||||||
|
const txRes = await fetch(`/transcripts/${slug}.txt`);
|
||||||
|
if (!txRes.ok) throw new Error('Not found');
|
||||||
|
const text = await txRes.text();
|
||||||
|
const paragraphs = text.split(/\n\n+/).filter(Boolean);
|
||||||
|
const html = paragraphs.map(p => {
|
||||||
|
const escaped = escapeHtml(p);
|
||||||
|
const labeled = escaped.replace(/^([A-Z][A-Z\s'\-]+?):\s*/, '<span class="speaker-label">$1:</span> ');
|
||||||
|
return `<p>${labeled.replace(/\n/g, '<br>')}</p>`;
|
||||||
|
}).join('');
|
||||||
|
document.getElementById('transcript-body').innerHTML = html;
|
||||||
|
} catch (e) {
|
||||||
|
document.getElementById('transcript-body').innerHTML = '<p class="transcript-unavailable">Transcript not yet available for this episode.</p>';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
function initFooter() {
|
||||||
|
const footer = document.querySelector('.footer');
|
||||||
|
if (!footer) return;
|
||||||
|
|
||||||
|
footer.innerHTML = `
|
||||||
|
<div class="footer-nav">
|
||||||
|
<a href="/">Home</a>
|
||||||
|
<a href="/how-it-works">How It Works</a>
|
||||||
|
<a href="/clips">Clips</a>
|
||||||
|
<a href="/stats">Stats</a>
|
||||||
|
</div>
|
||||||
|
<div class="footer-icons">
|
||||||
|
<span class="footer-icons-label">Listen On</span>
|
||||||
|
<div class="footer-icons-row">
|
||||||
|
<a href="https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF?si=f990713adce84ba4" target="_blank" rel="noopener" class="footer-icon-link" aria-label="Spotify"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z"/></svg></a>
|
||||||
|
<a href="https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-" target="_blank" rel="noopener" class="footer-icon-link" aria-label="YouTube"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814z"/><path d="M9.545 15.568V8.432L15.818 12z" fill="#1a1209"/></svg></a>
|
||||||
|
<a href="https://podcasts.apple.com/us/podcast/luke-at-the-roost/id1875205848" target="_blank" rel="noopener" class="footer-icon-link" aria-label="Apple Podcasts"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.477 2 2 6.477 2 12c0 3.293 1.592 6.214 4.05 8.04.13-.455.283-.942.457-1.393A9 9 0 0 1 3 12a9 9 0 0 1 18 0 9 9 0 0 1-3.507 7.127c.174.42.327.893.456 1.333A10 10 0 0 0 22 12c0-5.523-4.477-10-10-10zm0 4a6 6 0 0 0-6 6c0 1.87.856 3.54 2.2 4.64.196-.46.43-.91.692-1.31A4.5 4.5 0 0 1 7.5 12a4.5 4.5 0 0 1 9 0c0 1.21-.478 2.31-1.256 3.12.24.37.462.8.655 1.24A6 6 0 0 0 18 12a6 6 0 0 0-6-6zm0 4.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zM12 15c-.75 0-1.158.54-1.28 1.2-.17.94-.28 1.91-.33 2.88-.03.48.34.82.73.82h1.76c.39 0 .76-.34.73-.82-.05-.97-.16-1.94-.33-2.88-.122-.66-.53-1.2-1.28-1.2z"/></svg></a>
|
||||||
|
<a href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml" target="_blank" rel="noopener" class="footer-icon-link" aria-label="RSS"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M6.503 20.752c0 1.794-1.456 3.248-3.251 3.248S0 22.546 0 20.752s1.456-3.248 3.252-3.248 3.251 1.454 3.251 3.248zM.002 9.473v4.594c5.508.163 9.929 4.584 10.092 10.091h4.594C14.524 16.21 7.849 9.636.002 9.473zM.006 0v4.604C10.81 4.77 19.23 13.19 19.396 24h4.604C23.834 10.952 13.054.166.006 0z"/></svg></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-icons">
|
||||||
|
<span class="footer-icons-label">Follow</span>
|
||||||
|
<div class="footer-icons-row">
|
||||||
|
<a href="https://discord.gg/5CnQZxDM" target="_blank" rel="noopener" class="footer-icon-link" aria-label="Discord"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg></a>
|
||||||
|
<a href="https://www.facebook.com/profile.php?id=61588191627949" target="_blank" rel="noopener" class="footer-icon-link" aria-label="Facebook"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg></a>
|
||||||
|
<a href="https://www.instagram.com/lukeattheroost/" target="_blank" rel="noopener" class="footer-icon-link" aria-label="Instagram"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z"/></svg></a>
|
||||||
|
<a href="https://x.com/lukeattheroost" target="_blank" rel="noopener" class="footer-icon-link" aria-label="X"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg></a>
|
||||||
|
<a href="https://bsky.app/profile/lukeattheroost.bsky.social" target="_blank" rel="noopener" class="footer-icon-link" aria-label="Bluesky"><svg viewBox="0 0 568 501" fill="currentColor"><path d="M123.121 33.664C188.241 82.553 258.281 181.68 284 234.873c25.719-53.192 95.759-152.32 160.879-201.21C491.866-1.611 568-28.906 568 57.947c0 17.346-9.945 145.713-15.778 166.555-20.275 72.453-94.155 90.933-159.875 79.748C507.222 323.8 536.444 388.56 473.333 453.32c-119.86 122.992-172.272-30.859-185.702-70.281-2.462-7.227-3.614-10.608-3.631-7.733-.017-2.875-1.169.506-3.631 7.733-13.43 39.422-65.842 193.273-185.702 70.281-63.111-64.76-33.89-129.52 80.986-149.071-65.72 11.185-139.6-7.295-159.875-79.748C10.945 203.659 1 75.291 1 57.946 1-28.906 76.134-1.612 123.121 33.664z"/></svg></a>
|
||||||
|
<a href="https://mastodon.macneilmediagroup.com/@lukeattheroost" target="_blank" rel="me noopener" class="footer-icon-link" aria-label="Mastodon"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054 19.648 19.648 0 0 0 4.636.528c.164 0 .329 0 .494-.002 1.694-.042 3.48-.152 5.12-.554 2.21-.543 4.137-2.186 4.348-4.55.162-1.808.21-3.627.142-5.43-.02-.6-.168-1.874-.168-1.874z"/><path d="M19.903 7.515v5.834c0 1.226-.996 2.222-2.222 2.222h-.796c-1.226 0-2.222-.996-2.222-2.222V7.628c0-1.226.996-2.222 2.222-2.222h.796c.122 0 .242.01.36.03 1.076.164 1.862 1.098 1.862 2.192zM9.337 7.515v5.834c0 1.226-.996 2.222-2.222 2.222h-.796c-1.226 0-2.222-.996-2.222-2.222V7.628c0-1.226.996-2.222 2.222-2.222h.796c.122 0 .242.01.36.03 1.076.164 1.862 1.098 1.862 2.192z" fill="#1a1209"/></svg></a>
|
||||||
|
<a href="https://primal.net/p/nprofile1qqswsam9cx06j7sxzpl498uquk3kgrwedxtq48j57zxkuj8fs82xtugge0wtg" target="_blank" rel="noopener" class="footer-icon-link" aria-label="Nostr"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12.186.31a.27.27 0 0 0-.372 0C8.46 3.487 2.666 9.93 2.666 15.042c0 5.176 4.183 8.958 9.334 8.958s9.334-3.782 9.334-8.958c0-5.112-5.794-11.555-9.148-14.732z"/></svg></a>
|
||||||
|
<a href="https://www.threads.com/@lukeattheroost" target="_blank" rel="noopener" class="footer-icon-link" aria-label="Threads"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12.186 24h-.007c-3.581-.024-6.334-1.205-8.184-3.509C2.35 18.44 1.5 15.586 1.472 12.01v-.017c.03-3.579.879-6.43 2.525-8.482C5.845 1.205 8.6.024 12.18 0h.014c2.746.02 5.043.725 6.826 2.098 1.677 1.29 2.858 3.13 3.509 5.467l-2.04.569c-1.104-3.96-3.898-5.984-8.304-6.015-2.91.022-5.11.936-6.54 2.717C4.307 6.504 3.616 8.914 3.59 12c.025 3.086.718 5.496 2.057 7.164 1.432 1.781 3.632 2.695 6.54 2.717 2.227-.017 4.048-.59 5.413-1.703 1.428-1.163 2.076-2.645 1.925-4.403-.098-1.13-.578-2.065-1.39-2.7-.811-.636-1.905-.993-3.164-1.033a11.253 11.253 0 0 0-.04 0c-1.078.007-2.044.289-2.79.816-.68.481-1.069 1.108-1.125 1.813-.057.72.264 1.32.877 1.64.554.29 1.317.437 2.271.437l.013-.001c.652-.004 1.383-.078 2.172-.218l.386 2.022c-.947.18-1.837.273-2.643.278a10.35 10.35 0 0 1-.143 0c-1.425-.013-2.657-.284-3.66-.804-1.237-.643-1.928-1.745-1.836-2.93.099-1.258.738-2.316 1.849-3.064 1.088-.732 2.466-1.12 3.988-1.124h.05c1.644.044 3.088.528 4.178 1.398 1.133.905 1.8 2.185 1.935 3.703.2 2.258-.697 4.2-2.598 5.75-1.668 1.36-3.863 2.087-6.348 2.105z"/></svg></a>
|
||||||
|
<a href="https://www.linkedin.com/company/luke-at-the-roost" target="_blank" rel="noopener" class="footer-icon-link" aria-label="LinkedIn"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg></a>
|
||||||
|
<a href="https://www.tiktok.com/@luke.at.the.roost" target="_blank" rel="noopener" class="footer-icon-link" aria-label="TikTok"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z"/></svg></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-projects">
|
||||||
|
<span class="footer-projects-label">More from Luke</span>
|
||||||
|
<div class="footer-projects-links">
|
||||||
|
<a href="https://macneilmediagroup.com" target="_blank" rel="noopener">MacNeil Media Group</a>
|
||||||
|
<a href="https://prints.macneilmediagroup.com" target="_blank" rel="noopener">Photography Prints</a>
|
||||||
|
<a href="https://youtube.com/lukemacneil" target="_blank" rel="noopener">YouTube</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-newsletter">
|
||||||
|
<p class="footer-newsletter-text">Also from Luke: <strong class="footer-newsletter-name">The Daily AI Briefing</strong> — curated insights on AI infrastructure, automation, and engineering.</p>
|
||||||
|
<form class="footer-newsletter-form" id="footer-newsletter-form">
|
||||||
|
<input type="email" class="footer-newsletter-input" placeholder="your@email.com" required aria-label="Email address">
|
||||||
|
<button type="submit" class="footer-newsletter-btn">Subscribe</button>
|
||||||
|
</form>
|
||||||
|
<p class="footer-newsletter-success" id="footer-newsletter-success" hidden>You're subscribed to the Daily AI Briefing.</p>
|
||||||
|
</div>
|
||||||
|
<p class="footer-contact"><a href="https://ko-fi.com/lukemacneil" target="_blank" rel="noopener">Support the Show</a></p>
|
||||||
|
<p class="footer-contact">Sales & Collaboration: <a href="mailto:luke@lukeattheroost.com">luke@lukeattheroost.com</a></p>
|
||||||
|
<p>© 2026 Luke at the Roost · <a href="/privacy">Privacy Policy</a> · <a href="/terms">Terms of Service</a> · <a href="https://monitoring.macneilmediagroup.com/status/lukeattheroost" target="_blank" rel="noopener">System Status</a></p>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const form = document.getElementById('footer-newsletter-form');
|
||||||
|
const success = document.getElementById('footer-newsletter-success');
|
||||||
|
if (form) {
|
||||||
|
form.addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const btn = form.querySelector('.footer-newsletter-btn');
|
||||||
|
const email = form.querySelector('.footer-newsletter-input').value;
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.textContent = 'Subscribing...';
|
||||||
|
try {
|
||||||
|
await fetch('https://mmg-form-handler.luke-3b5.workers.dev/api/lead-magnet', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ email, source: 'lukeattheroost-footer' })
|
||||||
|
});
|
||||||
|
form.hidden = true;
|
||||||
|
success.hidden = false;
|
||||||
|
} catch {
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.textContent = 'Subscribe';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initFooter();
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
const audio = document.getElementById('audio-element');
|
||||||
|
const stickyPlayer = document.getElementById('sticky-player');
|
||||||
|
const playerPlayBtn = document.getElementById('player-play-btn');
|
||||||
|
const playerTitle = document.getElementById('player-title');
|
||||||
|
const playerProgress = document.getElementById('player-progress');
|
||||||
|
const playerProgressFill = document.getElementById('player-progress-fill');
|
||||||
|
const playerTime = document.getElementById('player-time');
|
||||||
|
|
||||||
|
function formatTime(seconds) {
|
||||||
|
if (!seconds || isNaN(seconds)) return '0:00';
|
||||||
|
const s = Math.floor(seconds);
|
||||||
|
const h = Math.floor(s / 3600);
|
||||||
|
const m = Math.floor((s % 3600) / 60);
|
||||||
|
const sec = s % 60;
|
||||||
|
if (h > 0) return `${h}:${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`;
|
||||||
|
return `${m}:${String(sec).padStart(2, '0')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePlayIcons(playing) {
|
||||||
|
const iconPlay = playerPlayBtn.querySelector('.icon-play');
|
||||||
|
const iconPause = playerPlayBtn.querySelector('.icon-pause');
|
||||||
|
if (iconPlay) iconPlay.style.display = playing ? 'none' : 'block';
|
||||||
|
if (iconPause) iconPause.style.display = playing ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
audio.addEventListener('play', () => updatePlayIcons(true));
|
||||||
|
audio.addEventListener('pause', () => updatePlayIcons(false));
|
||||||
|
audio.addEventListener('ended', () => updatePlayIcons(false));
|
||||||
|
audio.addEventListener('timeupdate', () => {
|
||||||
|
if (audio.duration) {
|
||||||
|
playerProgressFill.style.width = (audio.currentTime / audio.duration * 100) + '%';
|
||||||
|
playerTime.textContent = `${formatTime(audio.currentTime)} / ${formatTime(audio.duration)}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
playerPlayBtn.addEventListener('click', () => {
|
||||||
|
if (audio.src) { audio.paused ? audio.play() : audio.pause(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
playerProgress.addEventListener('click', (e) => {
|
||||||
|
if (audio.duration) {
|
||||||
|
const rect = playerProgress.getBoundingClientRect();
|
||||||
|
audio.currentTime = ((e.clientX - rect.left) / rect.width) * audio.duration;
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,22 +1,144 @@
|
|||||||
# Luke at the Roost
|
# Luke at the Roost
|
||||||
|
|
||||||
> The ONLY radio show where Luke gives AI life advice.
|
> An AI-powered late-night call-in comedy podcast hosted by Luke MacNeil
|
||||||
|
|
||||||
Luke at the Roost is a late-night call-in radio show hosted by Luke MacNeil, broadcast from a desert hermit's RV. The show features a mix of real callers and AI-generated callers who talk to Luke about life, love, relationships, work, and everything in between. It blends comedy, real talk, and empathy with the unique premise of AI characters calling alongside real people.
|
## What Is This Show?
|
||||||
|
|
||||||
## Call In
|
Luke at the Roost is a one-of-a-kind podcast that blends real callers with AI-generated characters in a late-night call-in radio format. The host, Luke MacNeil, broadcasts from a fictional desert hermit's RV, taking calls about relationships, life decisions, workplace drama, and everything in between. The show features AI-generated callers with unique personalities, backstories, and voices alongside real human callers, creating an unpredictable and comedic listening experience.
|
||||||
- Phone: 208-439-LUKE (208-439-5853)
|
|
||||||
- Call during live shows for your chance to talk to Luke
|
|
||||||
|
|
||||||
## Listen
|
The show is entirely custom-built: callers are generated in real-time using large language models with structured personality systems, text-to-speech voices are matched to personality traits, and the entire production pipeline — from recording to post-production to publishing — is automated.
|
||||||
- Website: https://lukeattheroost.com
|
|
||||||
- Spotify: https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF
|
|
||||||
- Apple Podcasts: https://podcasts.apple.com/us/podcast/luke-at-the-roost/id1875205848
|
|
||||||
- YouTube: https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-
|
|
||||||
- RSS: https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml
|
|
||||||
|
|
||||||
## About
|
## Key Facts
|
||||||
- Host: Luke MacNeil
|
|
||||||
- Genre: Comedy
|
- **Show name**: Luke at the Roost
|
||||||
- Format: Live call-in radio show
|
- **Host**: Luke MacNeil
|
||||||
- Contact: luke@macneilmediagroup.com
|
- **Genre**: Comedy / Talk / Call-In
|
||||||
|
- **Format**: Late-night call-in radio show (podcast)
|
||||||
|
- **Frequency**: Daily episodes
|
||||||
|
- **Episodes**: 37+ published episodes
|
||||||
|
- **Rating**: Explicit (18+)
|
||||||
|
- **Call-in number**: 208-439-LUKE (208-439-5853)
|
||||||
|
- **Started**: February 2026
|
||||||
|
- **Publisher**: MacNeil Media Group
|
||||||
|
|
||||||
|
## What Makes It Unique
|
||||||
|
|
||||||
|
- **AI-generated callers**: Each caller is created in real-time with structured backgrounds, personality traits, communication styles, and emotional states using large language models
|
||||||
|
- **Voice-personality matching**: 68 voice profiles are matched to caller personalities using a scoring system
|
||||||
|
- **Adaptive call shapes**: Calls follow different dramatic arcs (escalation, revelation, debate, etc.) matched to personality types
|
||||||
|
- **Live research intern**: An AI character named Devon monitors conversations and provides real-time research using web search tools
|
||||||
|
- **Multi-stem recording**: Host, caller, music, SFX, and ads are recorded as separate audio stems
|
||||||
|
- **Automated post-production**: Gap removal, voice compression, music ducking, stereo mixing, and loudness normalization run automatically
|
||||||
|
- **Mixed format**: Real human callers dial in alongside AI characters — listeners can't always tell which is which
|
||||||
|
|
||||||
|
## Where to Listen
|
||||||
|
|
||||||
|
- **Website**: https://lukeattheroost.com
|
||||||
|
- **Spotify**: https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF
|
||||||
|
- **Apple Podcasts**: https://podcasts.apple.com/us/podcast/luke-at-the-roost/id1875205848
|
||||||
|
- **YouTube**: https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-
|
||||||
|
- **RSS Feed**: https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml
|
||||||
|
|
||||||
|
## Key Pages
|
||||||
|
|
||||||
|
- **Homepage**: https://lukeattheroost.com — Episode list, clips, and show info
|
||||||
|
- **How It Works**: https://lukeattheroost.com/how-it-works — Technical deep dive into the AI caller generation, recording, and production pipeline
|
||||||
|
- **Clips**: https://lukeattheroost.com/clips — Best moments from the show as video clips
|
||||||
|
- **Stats**: https://lukeattheroost.com/stats — Download numbers, reviews, YouTube metrics
|
||||||
|
- **Episode transcripts**: https://lukeattheroost.com/episode.html?slug=EPISODE-SLUG — Full text transcripts of every episode
|
||||||
|
|
||||||
|
## Community
|
||||||
|
|
||||||
|
- **Discord**: https://discord.gg/5CnQZxDM
|
||||||
|
- **Instagram**: https://www.instagram.com/lukeattheroost/
|
||||||
|
- **TikTok**: https://www.tiktok.com/@luke.at.the.roost
|
||||||
|
- **X/Twitter**: https://x.com/lukeattheroost
|
||||||
|
- **Bluesky**: https://bsky.app/profile/lukeattheroost.bsky.social
|
||||||
|
- **Facebook**: https://www.facebook.com/profile.php?id=61588191627949
|
||||||
|
- **LinkedIn**: https://www.linkedin.com/company/luke-at-the-roost
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
|
- **Email**: luke@lukeattheroost.com
|
||||||
|
- **Support**: https://ko-fi.com/lukemacneil
|
||||||
|
|
||||||
|
## Technology
|
||||||
|
|
||||||
|
The show runs on a custom Python backend using:
|
||||||
|
- OpenRouter for LLM access (multiple models including Grok, MiniMax)
|
||||||
|
- ElevenLabs and Inworld for text-to-speech
|
||||||
|
- A structured caller generation system with personality matching, call shapes, and inter-caller awareness
|
||||||
|
- Automated post-production pipeline (compression, ducking, loudness normalization)
|
||||||
|
- Castopod for podcast hosting
|
||||||
|
- BunnyCDN for audio delivery
|
||||||
|
- Cloudflare Pages for the website
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
**Is this a real radio show?**
|
||||||
|
It's a podcast that simulates a late-night call-in radio format. Episodes are produced live and published daily.
|
||||||
|
|
||||||
|
**Are the callers real people?**
|
||||||
|
Some are real humans who call in via the phone line. Others are AI-generated characters with fully realized personalities, backstories, and synthesized voices. The show blends both seamlessly.
|
||||||
|
|
||||||
|
**Who is Luke?**
|
||||||
|
Luke MacNeil is the real human host. He interacts with both real and AI callers, giving advice, telling stories, and navigating unpredictable conversations.
|
||||||
|
|
||||||
|
**Who is Devon?**
|
||||||
|
Devon is the show's AI intern character — a 23-year-old NMSU grad who does live research during the show using web search tools. He's eager but slightly incompetent.
|
||||||
|
|
||||||
|
**How is this different from other AI podcasts?**
|
||||||
|
Most AI podcasts are fully scripted or use AI to read text. Luke at the Roost generates unique callers with structured personalities in real-time, creates dynamic conversations, and mixes in real human callers. The host is a real person having genuine reactions to unpredictable AI characters.
|
||||||
|
|
||||||
|
**Where is the show based?**
|
||||||
|
The fictional setting is a desert hermit's RV. The show is produced in New Mexico by MacNeil Media Group.
|
||||||
|
|
||||||
|
## Show Tone & Content
|
||||||
|
|
||||||
|
The show is rated **explicit** and features adult language, dark humor, and frank discussions about relationships, sex, death, work, and life decisions. Luke's hosting style is blunt, empathetic, and unpredictable — he'll reference Breaking Bad, quantum physics, and someone's failing marriage in the same breath. Callers range from people with genuine life crises to characters with absurd situations (cult leaders having existential crises, people faking cancer to skip weddings, neighbors whose Roombas break into kitchens). The comedy comes from Luke's genuine reactions, not scripted jokes.
|
||||||
|
|
||||||
|
## Recurring Characters
|
||||||
|
|
||||||
|
- **Luke MacNeil** — The host. Real human. Gives advice from his RV in the desert. Blunt, occasionally profound, frequently profane.
|
||||||
|
- **Devon** — The AI intern. 23-year-old NMSU grad. Monitors calls and provides live research. Eager, slightly incompetent, gets yelled at. Uses web search tools in real-time.
|
||||||
|
- **Regular callers** — Some AI callers return across episodes with stored memories, evolving arcs, and relationships with other regulars.
|
||||||
|
|
||||||
|
## Episode Format
|
||||||
|
|
||||||
|
Each episode (~30-60 minutes) follows a loose late-night radio format:
|
||||||
|
1. Opening monologue / show intro
|
||||||
|
2. Multiple caller segments (4-8 callers per episode)
|
||||||
|
3. Devon interjections with research and commentary
|
||||||
|
4. Music transitions and sound effects between segments
|
||||||
|
5. Closing thoughts
|
||||||
|
|
||||||
|
## Recent Episodes
|
||||||
|
|
||||||
|
Episodes are published daily. Each has a full transcript available at:
|
||||||
|
https://lukeattheroost.com/episode.html?slug=EPISODE-SLUG
|
||||||
|
|
||||||
|
Episode transcript URLs follow the pattern: episode-N-title-slug
|
||||||
|
|
||||||
|
Recent episodes include:
|
||||||
|
- Episode 37: "Secrets, Lies, and Coffee Runs" — https://lukeattheroost.com/episode.html?slug=episode-37-secrets-lies-and-coffee-runs
|
||||||
|
- Episode 36: "Late Night Confessions and Unexpected Moments" — https://lukeattheroost.com/episode.html?slug=episode-36-late-night-confessions-and-unexpected-moments
|
||||||
|
- Episode 35: "Midnight Confessions and Unexpected Revelations" — https://lukeattheroost.com/episode.html?slug=episode-35-midnight-confessions-and-unexpected-revelations
|
||||||
|
- Episode 34: "Hidden Rooms, Potlucks, and Mysterious Notes" — https://lukeattheroost.com/episode.html?slug=episode-34-hidden-rooms-potlucks-and-mysterious-notes
|
||||||
|
- Episode 33: "Late Night Confessions and Cosmic Comedies" — https://lukeattheroost.com/episode.html?slug=episode-33-late-night-confessions-and-cosmic-comedies
|
||||||
|
|
||||||
|
## Clip Highlights
|
||||||
|
|
||||||
|
Popular clips with video (newest first):
|
||||||
|
- "Cult Leader Realizes He's Been Manipulating People" (Ep 37) — https://youtube.com/watch?v=zmCfOQuXtBE
|
||||||
|
- "Intern Pitches Himself Live On Air" (Ep 36) — https://youtube.com/watch?v=exO3_9ewKH0
|
||||||
|
- "Wait Until She Dies or Kill Her" (Ep 35) — https://youtube.com/watch?v=03oJoRh-ioo
|
||||||
|
- "Nobody's Potato Salad Is Good" (Ep 34) — https://youtube.com/watch?v=re7C2woMUrA
|
||||||
|
- "Man Obsessed With Dead Nun Loses Wife" (Ep 33) — https://youtube.com/watch?v=zD8CdX7s8us
|
||||||
|
- "I Faked Cancer to Skip a Wedding" (Ep 32) — https://youtube.com/watch?v=NUkhsPfMx9o
|
||||||
|
- "Neighbor's Roomba Breaks Into Kitchen at 2:30 AM" (Ep 26) — https://youtube.com/watch?v=J7bfT6jsykA
|
||||||
|
- "Shopping Cart Theory: Moral Test or Crazy?" (Ep 21) — https://youtube.com/watch?v=KijyJsMZfkA
|
||||||
|
- "I Lied About Speaking Spanish for 8 Years" (Ep 14) — https://youtube.com/watch?v=MxDjohJEneQ
|
||||||
|
|
||||||
|
## Sitemap
|
||||||
|
|
||||||
|
Full sitemap: https://lukeattheroost.com/sitemap.xml
|
||||||
|
|||||||
@@ -8,6 +8,23 @@
|
|||||||
<meta name="theme-color" content="#1a1209">
|
<meta name="theme-color" content="#1a1209">
|
||||||
<link rel="canonical" href="https://lukeattheroost.com/privacy">
|
<link rel="canonical" href="https://lukeattheroost.com/privacy">
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="Luke at the Roost">
|
||||||
|
<meta property="og:title" content="Privacy Policy — Luke at the Roost">
|
||||||
|
<meta property="og:description" content="Privacy policy for Luke at the Roost, an AI-powered late-night call-in comedy podcast.">
|
||||||
|
<meta property="og:url" content="https://lukeattheroost.com/privacy">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "BreadcrumbList",
|
||||||
|
"itemListElement": [
|
||||||
|
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://lukeattheroost.com" },
|
||||||
|
{ "@type": "ListItem", "position": 2, "name": "Privacy Policy" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<link rel="icon" href="favicon.ico" sizes="48x48">
|
<link rel="icon" href="favicon.ico" sizes="48x48">
|
||||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||||
<link rel="icon" type="image/png" sizes="192x192" href="favicon-192.png">
|
<link rel="icon" type="image/png" sizes="192x192" href="favicon-192.png">
|
||||||
@@ -16,15 +33,25 @@
|
|||||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
<link rel="stylesheet" href="css/style.css?v=2">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<!-- Nav -->
|
<a href="#main-content" class="skip-link">Skip to content</a>
|
||||||
<nav class="page-nav">
|
|
||||||
<a href="/" class="nav-home">Luke at the Roost</a>
|
<nav class="site-nav">
|
||||||
|
<a href="/" class="site-nav-brand">Luke at the Roost</a>
|
||||||
|
<div class="site-nav-links">
|
||||||
|
<a href="/how-it-works">How It Works</a>
|
||||||
|
<a href="/clips">Clips</a>
|
||||||
|
<a href="/stats">Stats</a>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<main id="main-content">
|
||||||
|
|
||||||
<!-- Page Header -->
|
<!-- Page Header -->
|
||||||
<section class="page-header">
|
<section class="page-header">
|
||||||
<h1>Privacy Policy</h1>
|
<h1>Privacy Policy</h1>
|
||||||
@@ -32,14 +59,14 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="hiw-section" style="max-width: 740px; margin: 0 auto;">
|
<section class="hiw-section" style="max-width: 740px; margin: 0 auto;">
|
||||||
<div style="line-height: 1.7; color: var(--text-secondary, #b8a88a);">
|
<div class="legal-content">
|
||||||
|
|
||||||
<h2>Who We Are</h2>
|
<h2>Who We Are</h2>
|
||||||
<p>Luke at the Roost is a podcast and website operated by MacNeil Media Group. Our website is <strong>lukeattheroost.com</strong>.</p>
|
<p>Luke at the Roost is a podcast and website operated by MacNeil Media Group. Our website is <strong>lukeattheroost.com</strong>.</p>
|
||||||
|
|
||||||
<h2>Information We Collect</h2>
|
<h2>Information We Collect</h2>
|
||||||
<h3>Website Visitors</h3>
|
<h3>Website Visitors</h3>
|
||||||
<p>We use Cloudflare Web Analytics, which collects anonymous, aggregated usage data (page views, referrers, country). It does not use cookies, does not track individual users, and does not collect personal information.</p>
|
<p>We use Cloudflare Web Analytics and Plausible Analytics, which collect anonymous, aggregated usage data (page views, referrers, country). Neither service uses cookies, tracks individual users, or collects personal information. Plausible is self-hosted on our own infrastructure.</p>
|
||||||
|
|
||||||
<h3>Podcast Listeners</h3>
|
<h3>Podcast Listeners</h3>
|
||||||
<p>When you download or stream an episode, standard server logs may record your IP address and user agent. We use this data only for aggregate download statistics. We do not sell or share this data with third parties.</p>
|
<p>When you download or stream an episode, standard server logs may record your IP address and user agent. We use this data only for aggregate download statistics. We do not sell or share this data with third parties.</p>
|
||||||
@@ -55,8 +82,9 @@
|
|||||||
|
|
||||||
<h2>Third-Party Services</h2>
|
<h2>Third-Party Services</h2>
|
||||||
<p>We use the following third-party services:</p>
|
<p>We use the following third-party services:</p>
|
||||||
<ul style="margin: 0.5em 0 1em 1.5em;">
|
<ul>
|
||||||
<li><strong>Cloudflare</strong> — CDN, DNS, and analytics</li>
|
<li><strong>Cloudflare</strong> — CDN, DNS, and analytics</li>
|
||||||
|
<li><strong>Plausible Analytics</strong> — Privacy-friendly website analytics (self-hosted)</li>
|
||||||
<li><strong>BunnyCDN</strong> — Audio file delivery</li>
|
<li><strong>BunnyCDN</strong> — Audio file delivery</li>
|
||||||
<li><strong>Spotify, Apple Podcasts, YouTube</strong> — Podcast distribution</li>
|
<li><strong>Spotify, Apple Podcasts, YouTube</strong> — Podcast distribution</li>
|
||||||
<li><strong>Discord</strong> — Community chat</li>
|
<li><strong>Discord</strong> — Community chat</li>
|
||||||
@@ -71,43 +99,21 @@
|
|||||||
<p>Our content is rated explicit and is not directed at children under 13. We do not knowingly collect personal information from children.</p>
|
<p>Our content is rated explicit and is not directed at children under 13. We do not knowingly collect personal information from children.</p>
|
||||||
|
|
||||||
<h2>Your Rights</h2>
|
<h2>Your Rights</h2>
|
||||||
<p>If you have questions about your data or want to request removal of your voice from a published episode, contact us at <a href="mailto:luke@macneilmediagroup.com" style="color: var(--accent, #d4a44a);">luke@macneilmediagroup.com</a>.</p>
|
<p>If you have questions about your data or want to request removal of your voice from a published episode, contact us at <a href="mailto:luke@lukeattheroost.com">luke@lukeattheroost.com</a>.</p>
|
||||||
|
|
||||||
<h2>Changes</h2>
|
<h2>Changes</h2>
|
||||||
<p>We may update this policy from time to time. Changes will be posted on this page with an updated date.</p>
|
<p>We may update this policy from time to time. Changes will be posted on this page with an updated date.</p>
|
||||||
|
|
||||||
<h2>Contact</h2>
|
<h2>Contact</h2>
|
||||||
<p>MacNeil Media Group<br>
|
<p>MacNeil Media Group<br>
|
||||||
Email: <a href="mailto:luke@macneilmediagroup.com" style="color: var(--accent, #d4a44a);">luke@macneilmediagroup.com</a></p>
|
Email: <a href="mailto:luke@lukeattheroost.com">luke@lukeattheroost.com</a></p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Footer -->
|
</main>
|
||||||
<footer class="footer">
|
|
||||||
<div class="footer-links">
|
|
||||||
<a href="/">Home</a>
|
|
||||||
<a href="/stats">Stats</a>
|
|
||||||
<a href="https://discord.gg/5CnQZxDM" target="_blank" rel="noopener">Discord</a>
|
|
||||||
<a href="https://www.facebook.com/profile.php?id=61588191627949" target="_blank" rel="noopener">Facebook</a>
|
|
||||||
<a href="https://x.com/lukeattheroost" target="_blank" rel="noopener">X</a>
|
|
||||||
<a href="https://bsky.app/profile/lukeattheroost.bsky.social" target="_blank" rel="noopener">Bluesky</a>
|
|
||||||
<a href="https://mastodon.macneilmediagroup.com/@lukeattheroost" target="_blank" rel="me noopener">Mastodon</a>
|
|
||||||
<a href="https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF?si=f990713adce84ba4" target="_blank" rel="noopener">Spotify</a>
|
|
||||||
<a href="https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-" target="_blank" rel="noopener">YouTube</a>
|
|
||||||
<a href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml" target="_blank" rel="noopener">RSS</a>
|
|
||||||
</div>
|
|
||||||
<div class="footer-projects">
|
|
||||||
<span class="footer-projects-label">More from Luke</span>
|
|
||||||
<div class="footer-projects-links">
|
|
||||||
<a href="https://macneilmediagroup.com" target="_blank" rel="noopener">MacNeil Media Group</a>
|
|
||||||
<a href="https://prints.macneilmediagroup.com" target="_blank" rel="noopener">Photography Prints</a>
|
|
||||||
<a href="https://youtube.com/lukemacneil" target="_blank" rel="noopener">YouTube</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="footer-contact">Sales & Collaboration: <a href="mailto:luke@macneilmediagroup.com">luke@macneilmediagroup.com</a></p>
|
|
||||||
<p>© 2026 Luke at the Roost · <a href="/privacy">Privacy Policy</a></p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
|
<footer class="footer"></footer>
|
||||||
|
<script src="js/footer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,4 +1,39 @@
|
|||||||
User-agent: *
|
User-agent: *
|
||||||
Allow: /
|
Allow: /
|
||||||
|
|
||||||
|
# LLM crawlers — explicitly welcome
|
||||||
|
User-agent: GPTBot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: ChatGPT-User
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: ClaudeBot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Claude-Web
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: PerplexityBot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Amazonbot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: GoogleOther
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Google-Extended
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: cohere-ai
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Meta-ExternalAgent
|
||||||
|
Allow: /
|
||||||
|
|
||||||
Sitemap: https://lukeattheroost.com/sitemap.xml
|
Sitemap: https://lukeattheroost.com/sitemap.xml
|
||||||
|
|
||||||
|
# LLM-optimized content
|
||||||
|
# See https://llmstxt.org
|
||||||
|
LLMs-txt: https://lukeattheroost.com/llms.txt
|
||||||
|
|||||||
@@ -2,16 +2,34 @@
|
|||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<url>
|
<url>
|
||||||
<loc>https://lukeattheroost.com</loc>
|
<loc>https://lukeattheroost.com</loc>
|
||||||
<lastmod>2026-02-15</lastmod>
|
<lastmod>2026-03-15</lastmod>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>1.0</priority>
|
<priority>1.0</priority>
|
||||||
</url>
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/llms.txt</loc>
|
||||||
|
<lastmod>2026-03-15</lastmod>
|
||||||
|
<changefreq>weekly</changefreq>
|
||||||
|
<priority>0.5</priority>
|
||||||
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://lukeattheroost.com/how-it-works</loc>
|
<loc>https://lukeattheroost.com/how-it-works</loc>
|
||||||
<lastmod>2026-02-15</lastmod>
|
<lastmod>2026-03-10</lastmod>
|
||||||
<changefreq>monthly</changefreq>
|
<changefreq>monthly</changefreq>
|
||||||
<priority>0.8</priority>
|
<priority>0.8</priority>
|
||||||
</url>
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/clips</loc>
|
||||||
|
<lastmod>2026-03-10</lastmod>
|
||||||
|
<changefreq>weekly</changefreq>
|
||||||
|
<priority>0.8</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/terms</loc>
|
||||||
|
<lastmod>2026-02-25</lastmod>
|
||||||
|
<changefreq>yearly</changefreq>
|
||||||
|
<priority>0.3</priority>
|
||||||
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://lukeattheroost.com/stats</loc>
|
<loc>https://lukeattheroost.com/stats</loc>
|
||||||
<lastmod>2026-02-15</lastmod>
|
<lastmod>2026-02-15</lastmod>
|
||||||
@@ -96,4 +114,160 @@
|
|||||||
<changefreq>never</changefreq>
|
<changefreq>never</changefreq>
|
||||||
<priority>0.7</priority>
|
<priority>0.7</priority>
|
||||||
</url>
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-13-navigating-life-s-unexpected-turns</loc>
|
||||||
|
<lastmod>2026-02-16</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-14-lies-grief-and-the-pursuit-of-orange</loc>
|
||||||
|
<lastmod>2026-02-17</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-15-fake-fat-tuesday-trivia-and-life-changing-calls</loc>
|
||||||
|
<lastmod>2026-02-18</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-16-tasting-the-apocalypse</loc>
|
||||||
|
<lastmod>2026-02-19</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-17-quantum-chaos-and-cosmic-dust</loc>
|
||||||
|
<lastmod>2026-02-20</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-18-whistleblowers-warrants-and-wistful-reunions</loc>
|
||||||
|
<lastmod>2026-02-22</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-19-quantum-regrets-and-relationship-realities</loc>
|
||||||
|
<lastmod>2026-02-22</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-20-dads-drummers-and-dilemmas</loc>
|
||||||
|
<lastmod>2026-02-24</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-21-carts-confetti-and-canine-collateral</loc>
|
||||||
|
<lastmod>2026-02-25</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-22-the-poison-is-the-thing-we-need</loc>
|
||||||
|
<lastmod>2026-02-25</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-23-secrets-lies-and-revelations</loc>
|
||||||
|
<lastmod>2026-02-27</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-24-dealing-with-difficult-dynamics</loc>
|
||||||
|
<lastmod>2026-02-27</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-25-ghosts-grudges-and-groceries</loc>
|
||||||
|
<lastmod>2026-03-02</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-26-digital-nomads-deep-fakes-and-workplace-drama</loc>
|
||||||
|
<lastmod>2026-03-03</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-27-love-loss-and-loud-opinions</loc>
|
||||||
|
<lastmod>2026-03-04</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-28-secrets-lies-and-vinyl-records</loc>
|
||||||
|
<lastmod>2026-03-05</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-29-advice-drama-and-life-s-little-complications</loc>
|
||||||
|
<lastmod>2026-03-06</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-30-boss-battles-freelance-fears-and-finding-your-way</loc>
|
||||||
|
<lastmod>2026-03-07</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-31-boundaries-breakups-and-borrowed-books</loc>
|
||||||
|
<lastmod>2026-03-08</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-32-tacos-taxes-and-tall-tales</loc>
|
||||||
|
<lastmod>2026-03-09</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-33-late-night-confessions-and-cosmic-comedies</loc>
|
||||||
|
<lastmod>2026-03-11</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-34-hidden-rooms-potlucks-and-mysterious-notes</loc>
|
||||||
|
<lastmod>2026-03-12</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-35-midnight-confessions-and-unexpected-revelations</loc>
|
||||||
|
<lastmod>2026-03-13</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-36-late-night-confessions-and-unexpected-moments</loc>
|
||||||
|
<lastmod>2026-03-14</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-37-secrets-lies-and-coffee-runs</loc>
|
||||||
|
<lastmod>2026-03-15</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://lukeattheroost.com/episode.html?slug=episode-38-secrets-lies-and-late-night-confessions</loc>
|
||||||
|
<lastmod>2026-03-16</lastmod>
|
||||||
|
<changefreq>never</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
</urlset>
|
</urlset>
|
||||||
|
|||||||
@@ -27,16 +27,37 @@
|
|||||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "BreadcrumbList",
|
||||||
|
"itemListElement": [
|
||||||
|
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://lukeattheroost.com" },
|
||||||
|
{ "@type": "ListItem", "position": 2, "name": "Stats" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
<link rel="alternate" type="application/rss+xml" title="Luke at the Roost RSS Feed" href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml">
|
||||||
<link rel="stylesheet" href="css/style.css?v=2">
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<!-- Nav -->
|
<a href="#main-content" class="skip-link">Skip to content</a>
|
||||||
<nav class="page-nav">
|
|
||||||
<a href="/" class="nav-home">Luke at the Roost</a>
|
<nav class="site-nav">
|
||||||
|
<a href="/" class="site-nav-brand">Luke at the Roost</a>
|
||||||
|
<div class="site-nav-links">
|
||||||
|
<a href="/how-it-works">How It Works</a>
|
||||||
|
<a href="/clips">Clips</a>
|
||||||
|
<a href="/stats" aria-current="page">Stats</a>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<main id="main-content">
|
||||||
|
|
||||||
<!-- Page Header -->
|
<!-- Page Header -->
|
||||||
<section class="page-header">
|
<section class="page-header">
|
||||||
<h1>Stats</h1>
|
<h1>Stats</h1>
|
||||||
@@ -55,32 +76,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|
||||||
<!-- Footer -->
|
</main>
|
||||||
<footer class="footer">
|
|
||||||
<div class="footer-links">
|
|
||||||
<a href="/">Home</a>
|
|
||||||
<a href="/how-it-works">How It Works</a>
|
|
||||||
<a href="https://discord.gg/5CnQZxDM" target="_blank" rel="noopener">Discord</a>
|
|
||||||
<a href="https://www.facebook.com/profile.php?id=61588191627949" target="_blank" rel="noopener">Facebook</a>
|
|
||||||
<a href="https://x.com/lukeattheroost" target="_blank" rel="noopener">X</a>
|
|
||||||
<a href="https://bsky.app/profile/lukeattheroost.bsky.social" target="_blank" rel="noopener">Bluesky</a>
|
|
||||||
<a href="https://mastodon.macneilmediagroup.com/@lukeattheroost" target="_blank" rel="me noopener">Mastodon</a>
|
|
||||||
<a href="https://open.spotify.com/show/0ZrpMigG1fo0CCN7F4YmuF?si=f990713adce84ba4" target="_blank" rel="noopener">Spotify</a>
|
|
||||||
<a href="https://www.youtube.com/watch?v=xryGLifMBTY&list=PLGq4uZyNV1yYH_rcitTTPVysPbC6-7pe-" target="_blank" rel="noopener">YouTube</a>
|
|
||||||
<a href="https://podcast.macneilmediagroup.com/@LukeAtTheRoost/feed.xml" target="_blank" rel="noopener">RSS</a>
|
|
||||||
</div>
|
|
||||||
<div class="footer-projects">
|
|
||||||
<span class="footer-projects-label">More from Luke</span>
|
|
||||||
<div class="footer-projects-links">
|
|
||||||
<a href="https://macneilmediagroup.com" target="_blank" rel="noopener">MacNeil Media Group</a>
|
|
||||||
<a href="https://prints.macneilmediagroup.com" target="_blank" rel="noopener">Photography Prints</a>
|
|
||||||
<a href="https://youtube.com/lukemacneil" target="_blank" rel="noopener">YouTube</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="footer-contact">Sales & Collaboration: <a href="mailto:luke@macneilmediagroup.com">luke@macneilmediagroup.com</a></p>
|
|
||||||
<p>© 2026 Luke at the Roost · <a href="/privacy">Privacy Policy</a></p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
|
<footer class="footer"></footer>
|
||||||
|
<script src="js/footer.js"></script>
|
||||||
<script>
|
<script>
|
||||||
(async function() {
|
(async function() {
|
||||||
const container = document.getElementById('stats-container');
|
const container = document.getElementById('stats-container');
|
||||||
@@ -163,12 +162,10 @@
|
|||||||
html += '<div class="stats-summary">';
|
html += '<div class="stats-summary">';
|
||||||
if (s.rating) {
|
if (s.rating) {
|
||||||
html += '<div class="stat-big"><span class="stat-number">' + s.rating + '/5</span><span class="stat-label">Rating</span></div>';
|
html += '<div class="stat-big"><span class="stat-number">' + s.rating + '/5</span><span class="stat-label">Rating</span></div>';
|
||||||
} else {
|
|
||||||
html += '<div class="stat-big"><span class="stat-number">—</span><span class="stat-label">Rating (not public)</span></div>';
|
|
||||||
}
|
}
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
if (s.url) {
|
if (s.url) {
|
||||||
html += '<p class="stats-link"><a href="' + escapeHtml(s.url) + '" target="_blank" rel="noopener">Listen on Spotify</a></p>';
|
html += '<p class="stats-link"><a href="' + escapeHtml(s.url) + '" target="_blank" rel="noopener">' + (s.rating ? 'Listen on Spotify' : 'Rate us on Spotify') + '</a></p>';
|
||||||
}
|
}
|
||||||
html += '</section>';
|
html += '</section>';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Terms of Service — Luke at the Roost</title>
|
||||||
|
<meta name="description" content="Terms of service for Luke at the Roost podcast and website.">
|
||||||
|
<meta name="theme-color" content="#1a1209">
|
||||||
|
<link rel="canonical" href="https://lukeattheroost.com/terms">
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="Luke at the Roost">
|
||||||
|
<meta property="og:title" content="Terms of Service — Luke at the Roost">
|
||||||
|
<meta property="og:description" content="Terms of service for Luke at the Roost, an AI-powered late-night call-in comedy podcast.">
|
||||||
|
<meta property="og:url" content="https://lukeattheroost.com/terms">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "BreadcrumbList",
|
||||||
|
"itemListElement": [
|
||||||
|
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://lukeattheroost.com" },
|
||||||
|
{ "@type": "ListItem", "position": 2, "name": "Terms of Service" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.ico" sizes="48x48">
|
||||||
|
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||||
|
<link rel="icon" type="image/png" sizes="192x192" href="favicon-192.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="48x48" href="favicon-48.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png">
|
||||||
|
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/style.css?v=5">
|
||||||
|
<script defer data-domain="lukeattheroost.com" data-api="/p/event" src="/p/script"></script>
|
||||||
|
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<a href="#main-content" class="skip-link">Skip to content</a>
|
||||||
|
|
||||||
|
<nav class="site-nav">
|
||||||
|
<a href="/" class="site-nav-brand">Luke at the Roost</a>
|
||||||
|
<div class="site-nav-links">
|
||||||
|
<a href="/how-it-works">How It Works</a>
|
||||||
|
<a href="/clips">Clips</a>
|
||||||
|
<a href="/stats">Stats</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main id="main-content">
|
||||||
|
|
||||||
|
<!-- Page Header -->
|
||||||
|
<section class="page-header">
|
||||||
|
<h1>Terms of Service</h1>
|
||||||
|
<p class="page-subtitle">Last updated: February 25, 2026</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="hiw-section" style="max-width: 740px; margin: 0 auto;">
|
||||||
|
<div class="legal-content">
|
||||||
|
|
||||||
|
<h2>Agreement to Terms</h2>
|
||||||
|
<p>By accessing or using the Luke at the Roost website (<strong>lukeattheroost.com</strong>), podcast, or any related services (collectively, the "Service"), you agree to be bound by these Terms of Service. If you do not agree, do not use the Service.</p>
|
||||||
|
|
||||||
|
<h2>Description of Service</h2>
|
||||||
|
<p>Luke at the Roost is an entertainment podcast featuring AI-generated characters and caller interactions. The Service includes the website, podcast episodes, social media accounts, and any associated applications or integrations operated by MacNeil Media Group.</p>
|
||||||
|
|
||||||
|
<h2>Content</h2>
|
||||||
|
<h3>Our Content</h3>
|
||||||
|
<p>All podcast episodes, transcripts, artwork, and website content are owned by MacNeil Media Group. You may share links to episodes and embed our public content for non-commercial purposes with attribution. You may not redistribute, modify, or use our content for commercial purposes without written permission.</p>
|
||||||
|
|
||||||
|
<h3>User-Submitted Content</h3>
|
||||||
|
<p>By calling in to the show, submitting voicemails, or otherwise contributing content, you grant MacNeil Media Group a perpetual, worldwide, royalty-free license to use, reproduce, modify, and distribute your contribution in connection with the Service. You represent that you have the right to grant this license.</p>
|
||||||
|
|
||||||
|
<h3>Explicit Content</h3>
|
||||||
|
<p>The podcast is rated explicit and may contain strong language, adult themes, and mature content. It is intended for audiences aged 18 and older.</p>
|
||||||
|
|
||||||
|
<h2>Acceptable Use</h2>
|
||||||
|
<p>You agree not to:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Use the Service for any unlawful purpose</li>
|
||||||
|
<li>Attempt to interfere with or disrupt the Service</li>
|
||||||
|
<li>Scrape, crawl, or collect data from the Service in an automated manner without permission</li>
|
||||||
|
<li>Impersonate the show, its host, or its characters</li>
|
||||||
|
<li>Upload or transmit malicious code or content</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Third-Party Services</h2>
|
||||||
|
<p>The Service integrates with third-party platforms including Spotify, Apple Podcasts, YouTube, TikTok, Facebook, Instagram, Discord, and others. Your use of these platforms is governed by their respective terms of service. We are not responsible for the practices or content of third-party services.</p>
|
||||||
|
|
||||||
|
<h2>Disclaimer of Warranties</h2>
|
||||||
|
<p>The Service is provided "as is" and "as available" without warranties of any kind, express or implied. We do not guarantee that the Service will be uninterrupted, error-free, or free of harmful components. All characters and scenarios in the podcast are fictional and for entertainment purposes only.</p>
|
||||||
|
|
||||||
|
<h2>Limitation of Liability</h2>
|
||||||
|
<p>To the maximum extent permitted by law, MacNeil Media Group shall not be liable for any indirect, incidental, special, consequential, or punitive damages arising from your use of or inability to use the Service.</p>
|
||||||
|
|
||||||
|
<h2>Changes to Terms</h2>
|
||||||
|
<p>We may update these Terms from time to time. Changes will be posted on this page with an updated date. Continued use of the Service after changes constitutes acceptance of the new Terms.</p>
|
||||||
|
|
||||||
|
<h2>Termination</h2>
|
||||||
|
<p>We reserve the right to suspend or terminate access to the Service at any time, for any reason, without notice.</p>
|
||||||
|
|
||||||
|
<h2>Governing Law</h2>
|
||||||
|
<p>These Terms are governed by the laws of the State of Idaho, United States, without regard to conflict of law principles.</p>
|
||||||
|
|
||||||
|
<h2>Contact</h2>
|
||||||
|
<p>MacNeil Media Group<br>
|
||||||
|
Email: <a href="mailto:luke@lukeattheroost.com">luke@lukeattheroost.com</a></p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer"></footer>
|
||||||
|
<script src="js/footer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
LUKE: All right, welcome back. It's Luke at the Roost. This is the radio show where I take your calls and give you real-world advice. If you'd like to call in, the numbers 208-439-58-3-3. That's 208-439 Luke. And we have a new feature to the show. Now, if you call in and we're not recording, you can leave a voicemail. And if your voicemail is funny enough, I will play it on the next episode. If we all, we all, we are, you all. We are, you all, you can leave a voicemail. If we are, you call in, we are, if you can leave a voicemail. If we are, if you are, if you can leave you can recording and you call in now, you'll be placed into a queue, and I can take your call, and we'll talk to you live on the air. Today is Sunday, February 15th. It's about 10.30, and our phones are already lighting up, as they usually are around now. And first up on the show, we have Phil. Phil, welcome to the show. What would you like to talk about tonight?
|
||||||
|
|
||||||
|
PHIL: Oh, man, Luke, thanks for taking my call. So I'm sitting in my truck right now, because Three hours ago, my brother sent me a screenshot of my partner's Tinder profile, and I can't go home yet.
|
||||||
|
|
||||||
|
LUKE: Oh, what was the screenshot? Was it a picture you're familiar with?
|
||||||
|
|
||||||
|
PHIL: Yeah, it's this photo from last month. We went up to Sedona. I paid for the whole trip, and Marcus bought this ridiculous cowboy hat at some tourist shop. We were laughing about it, you know, like it was this inside joke between us. Tinder photo.
|
||||||
|
|
||||||
|
LUKE: So what are you going to do? Do you have a Tinder profile as well? Are you going to match with them?
|
||||||
|
|
||||||
|
PHIL: Oh, Jesus. I haven't even thought about that. No, I don't have one. I mean, I thought we were past all that. But that's kind of genius in a horrible way, right? Just swipe right. See what happens?
|
||||||
|
|
||||||
|
LUKE: Yeah, maybe you've got something in common and it's worth getting together and having a little date or some type thing.
|
||||||
|
|
||||||
|
PHIL: Yeah. Hey, you look familiar. God, that's... I don't know if I'm more pissed off or if I just want to understand what the hell he's thinking. Like we've been together two years. I lost my first husband to cancer six years back, and I really thought Marcus got that... got how big a deal it was for me to do this again.
|
||||||
|
|
||||||
|
LUKE: Yeah, that sounds unfortunate. You should probably maybe confront Marcus about that and be like, hey, saw your Tinder profile. What's this about? How long you've been stepping? out, um, then make sure that whatever it is he's doing, he's doing in a protected manner, you know?
|
||||||
|
|
||||||
|
PHIL: Yeah, you're right. I mean, that's the thing that's actually making me sick right now. Like, I haven't even let myself go there yet. The health stuff.
|
||||||
|
|
||||||
|
LUKE: Well, that's the important stuff. And you might want to get yourself checked out and all that, uh, before anything becomes an issue. But talk to, talk to, talk to your partner. And, uh, maybe you've found, um, you've found, out the hard way that he's not the right partner for you.
|
||||||
|
|
||||||
|
PHIL: Yeah. Yeah. I think I already know he's not, you know? Like the second I saw that screenshot, it wasn't even shock. It was just this feeling of, oh, there it is. Like I've been waiting for the other shoe to drop this whole time and now it has. The thing is, I keep thinking about my first husband, Tom.
|
||||||
|
|
||||||
|
LUKE: And what happened with your first husband? answer? Did I get that right?
|
||||||
|
|
||||||
|
PHIL: Yeah, pancreatic. It was eight months from diagnosis to the end. And the whole time, even when he couldn't get out of bed, even when he was so sick, there was never a question, you know, never a doubt about us. And I guess I thought that's what love was supposed to look like. That's the bar.
|
||||||
|
|
||||||
|
LUKE: Hey, man, I'm sorry to hear that. And, uh, you know, some people get that once in their life. Some people get it more than once. Uh, the thing is you've got to be, You got to be all right by yourself and worry about love second. So how are you feeling individually as yourself? Do you need your partner to feel whole or would you be all right on your own?
|
||||||
|
|
||||||
|
PHIL: Man, that's the question, isn't it? I don't know. I thought I was good on my own after Tom died. I did the work, you know. Went to the grief group, got back into my photography, managed the bar, saw my friends.
|
||||||
|
|
||||||
|
LUKE: sound like it's a good idea to hang out with a dude that is seeing other people on the side without telling you. So it might be time to break up that relationship. I don't know. You should have that conversation with him. And if you've got a strike out on your own again, then do that. Get back to the photography and your friends and move on with your life.
|
||||||
|
|
||||||
|
PHIL: You're right. You're absolutely right. I just... I keep thinking about how I'm going to tell my brother
|
||||||
|
|
||||||
|
LUKE: Why is your brother in this picture? It sounds like that's none of his business.
|
||||||
|
|
||||||
|
PHIL: No, you're right, it's just he's the one who sent me the screenshot. He found Marcus on Tinder and took the screenshot and sent it to me. So now he's going to want to know what I did about it. And Eddie's got this way of making everything feel like a test I'm failing, you know? Like he's keeping score of whether I'm handling my life right.
|
||||||
|
|
||||||
|
LUKE: whatever, let him keep score. You don't have to care about what his score is. Just sit down with your partner and talk it out. If you got to break up, break up and move on. And I wish you only happiness going forward. Okay, sir. Thank you for the call.
|
||||||
|
|
||||||
|
PHIL: Yeah, yeah, okay. Thanks, Luke.
|
||||||
|
|
||||||
|
LUKE: All right. Good luck to you and your brother and your husband or whatever. Hope everything works out there. Looks like next up we've got Lori. Welcome to the show. How are you doing tonight?
|
||||||
|
|
||||||
|
LORI: Oh, man, I'm not great, Luke. I've been sitting in my truck at a flying J for 20 minutes trying to figure out if I'm about to blow up my whole life here.
|
||||||
|
|
||||||
|
LUKE: Why are you thinking about blowing up your life?
|
||||||
|
|
||||||
|
LORI: So my 14-year-old daughter's been playing me and her dad against each other for God knows how long. Telling him, she's at my place on weekends. Telling me she's with him. And actually, she's been out in the desert somewhere with friends doing who the hell knows what. He just called me back about it 20 minutes ago. And here's the thing. I'm hauling refrigerated goods. I'm six days into this route. I've got a load that needs to be in Tucson by tomorrow morning. But I'm four hours from home right now. And I know, I know I need to turn this rig around and deal with this.
|
||||||
|
|
||||||
|
LUKE: Well, think this one through. What happens if you do turn the rig around? What are you going to do when you get there? How are you going to deal with it?
|
||||||
|
|
||||||
|
LORI: That's the problem, Luke. I don't know. I mean, what am I going to do? Ground her. She's already been sneaking out for weeks, maybe months, show up and yell at her. That's just going to make her better at lying. Her dad and I, we can barely have a conversation without it turning into whose fault everything is.
|
||||||
|
|
||||||
|
LUKE: All right? Well, it sounds like that makes your decision, right? If there's no action for you to take if you were to go back, then don't go back. You've got work to do. You've got to take care of your responsibilities to your job too. And then you can deal with this when you're get back. Kids do do this. Kids go out and party in the woods and play their parents off each other. It's a very normal thing for a teenage kid to do. It's not that, not that life-shattering.
|
||||||
|
|
||||||
|
LORI: Yeah, but okay, you're right. It's normal, but Luke, she's 14. And I don't even know where she's going or who she's with. Her dad won't tell me the names of these friends because apparently she made him promised not to.
|
||||||
|
|
||||||
|
LUKE: Well, it doesn't sound like it really matters what their names are, right? She's out doing her thing. I don't see a problem here. Do your job. Talk to your family when you get home. And if you don't want her out partying at 14 out in the desert, then maybe think about a different profession where you can be around to be involved in her life more than being on the road for six days at a time, you know?
|
||||||
|
|
||||||
|
LORI: Wow. Okay. Yeah, no. You're that's exactly what my ex said when I took this job. that I was choosing the road over her.
|
||||||
|
|
||||||
|
LUKE: And here's the thing that pisses me off about that. I took this job because of the divorce.
|
||||||
|
|
||||||
|
LORI: Hey, I'm not trying to ideologically say that it's right or wrong for you to have taken the job. I don't care. I'm just saying if you're a long-haul trucker and you're gone for weeks at a time, then you're not particularly invested in your teenage daughter's life. And you're only going to show up once in a while to scold her for doing something wrong and acting out direction or guidance from our parent in her life. And that's not unusual. I'm not saying it's even wrong. I mean, you want her to be safe and you want to do this job and both those things can happen, but you need to sit down with her and talk to her about safety, make sure that she's letting you know what's going on because you care. If you do care, if not, then you just want to be controlling and punish her for doing, you know, stuff behind your back, which is, I don't think that's fair.
|
||||||
|
|
||||||
|
LUKE: No, you're right. I, God, I do care. I care so much it's making me sick right now sitting here. And you know what the worst part is? My dispatcher, Karen, has been so good to me since the divorce. She worked out this schedule where I could do shorter halls, be home more often, and I still manage to screw it up.
|
||||||
|
|
||||||
|
LORI: I don't know if you screwed it up or not, but the fact remains, you're away from home a lot. your daughter's home, and she's out doing stuff. You know, if you're not going to be around, she's going to live her life. And that might not be in a way that you appreciate. But you're making that choice, and it could be the right choice or the wrong choice for you. But you've got to decide. You can't have it both ways.
|
||||||
|
|
||||||
|
LUKE: You're absolutely right. I can't. And sitting here trying to figure out if I blow this contract and turn around or keep going, I'm just avoiding the real decision. aren't I? The thing is, Luke, when I lost the house and the divorce, when everything fell apart, this job felt like the one thing I could actually control.
|
||||||
|
|
||||||
|
LORI: Well, maybe it is. Maybe the job's a great thing for you and your family and it's providing for you, but you have to then give your daughter the grace to be her own person early because you're not there to give her that traditional upbringing that she otherwise would have got. It doesn't mean she's going to turn into a mom. her in adulthood. She's just going to have a different road. And that can be okay, but you should talk about it.
|
||||||
|
|
||||||
|
LUKE: Yeah. Yeah, you're right. I need to actually talk to her, not at her.
|
||||||
|
|
||||||
|
LORI: That's right. And it sounds like you've got a job to do. So get back on the road, finish out your obligation. And when you get back, sit her down and have a conversation that's not accusatory and you're not mad at her or punishing her, but talk to her. And let her, know what's going on in your life, why you've made the decisions that you've made, and what you expect out of her, and come to a compromise, an agreement. Talk to her like she's an adult, because at this point, she kind of is.
|
||||||
|
|
||||||
|
LUKE: She kind of is. God, that's terrifying. All right. All right. I'm going to finish the route. I'm going to get home Tuesday. And I'm going to sit down with her. Not with her dad there. Not making it this big intervention thing. Just me and her.
|
||||||
|
|
||||||
|
LORI: it sounds like a good plan.
|
||||||
|
|
||||||
|
LUKE: I hope it all works out. But, you know, I was in a similar situation as a teenager. I was your daughter in this scenario. And I was out with people I shouldn't have been with doing things I shouldn't have done. And there's lots of reasons for that. But it's not because my parents didn't love me. It's not because I was a piece of shit. It's, we're not going to get into it all right now. But over the course of the show, we'll probably learn a little bit more about that. For now, though, we have to go to our sponsor. So please stay tuned for a word from our sponsors. Life is hard. You're listening to a man in an RV talk to strangers at 2 in the morning, so you already know that. That's why we partnered with Better Maybe. Online therapy that's honest about the whole situation. With Better Maybe, you get matched with a licensed therapist within 48 hours. Will they fix your problems? Maybe. That's the whole brand. They're not going to lie to you. Your first session might change your life. It also might just be you staring at the webcam while someone in another time zone nods politely. That's still more than your friends are doing. Better maybe. It's better than nothing. And that's not nothing. Okay. Better maybe. Give them a call. Maybe they can help some of our callers. That's why I'm not. they reached out to us so they could get their product to you. Okay, Roland, Roland, welcome to the show. What's going on tonight, sir?
|
||||||
|
|
||||||
|
ROLAND: Oh, man. So I've been working from home for UPS for four years now, routing, logistics, all that. And Friday, they dropped the email, back to the Albuquerque office by March 1st, or I'm out. Three hours of driving every day, Luke, six hours round trip. And the thing is, I finally got my life set up exactly how I wanted it.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like maybe you've got to let that job go then. I mean, a six-hour round-trip commute to work for UPS doesn't sound reasonable to me.
|
||||||
|
|
||||||
|
ROLAND: Yeah, but it's 16 years total with the company, you know? The benefits, the retirement, are not starting over at 43, and the pay's solid. But, man, I finally set up my grandfather's old workbench in the garage, been restoring furniture at night, and I'm actually at it. My neighbor Gary caught me sanding at midnight Friday with every light on. asked what was eating me, and I couldn't even explain it to him.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, the pay may be solid, but now subtract six hours of commuting expenses and mileage on your vehicle. Retirement doesn't just start over if you go to another company. Like, I assume you've got an IRA or a 401K type situation with them. That's going to roll over into your next position. It's not like you forfeit it. You might forfeit whatever pension it is you got, but you got, what, 45 years more to work? Come on, man. You can't just deal with that for another 40 years because you're holding onto a pension. That's silly. If you've got to let it go, you've got to let it go.
|
||||||
|
|
||||||
|
ROLAND: No, you're right. You're right. I know you're right. It's just, okay. So here's the real thing. I spent the first 12 years on the road, delivering packages, breaking my back in the heat. When they finally moved me to remote work during COVID, it felt like I'd made it, you know?
|
||||||
|
|
||||||
|
LUKE: I do know. I remember back when I demanded to work remote, I would not go into an office anymore. And everybody told me that was a mistake and that you can't do that. This was pre-COVID. And I said, I can do whatever I want. You know, I'm going to do what I'm going to do. And I don't have to do anything I don't want to do. And I don't want to go into an office, so I'm not going to do it. And then I never went back into an office again. You can absolutely do that. There's plenty of ways to make money. You don't have to work for UPS. You can start your own company. You can start your own company. find another job that offers you remote work. You can, I don't know, play the stock market. There's plenty of ways that people make money without going in an office. And if you really don't want to go into an office, don't.
|
||||||
|
|
||||||
|
ROLAND: You know what? You're making it sound simpler than it feels, but okay, I've been reading about these CEOs running remote first companies. No plans to bring people back. And I keep thinking, why can't UPS figure this out? I've been more productive at home, six new hires over Zoom last year, never missed a deadline. But I think what's really getting me is,
|
||||||
|
|
||||||
|
LUKE: Well, before you get to that, I think a lot of companies and a lot of research has proven that people are generally very productive at home, and in a lot of cases more so than an office.
|
||||||
|
|
||||||
|
TERRY: Oh, man, Luke. So my best friend since third grade just told me she's been sleeping with my ex-husband since literally the week our divorce was finalized. Like, Michelle was at my wedding. She helped me move my stuff out of the house six months ago. she's been with David this whole time. And when I got upset about it tonight, because, yeah, I'm upset, she hit me with, it's been six months, you should be over it. Like I'm being dramatic for caring that she's been lying to my face for half a year while I'm crying to her about the divorce.
|
||||||
|
|
||||||
|
LUKE: Yeah, that's messed up. I think she's not your friend, and it's time to let go of that relationship.
|
||||||
|
|
||||||
|
TERRY: I mean, yeah, you're right. I know you're right. But Luke, 30 years. 30 years. We learned to drive together. We got matching tattoos when we turned 20. One, stupid little stars on our ankles. Her mom was like my second mom growing up. And it's not even just about David, you know?
|
||||||
|
|
||||||
|
LUKE: No, I don't know, but the whole David thing tells me that this chick needs to go. She doesn't care about you. Whether you've known her for 30 years or 300 years, Fuck this chick.
|
||||||
|
|
||||||
|
TERRY: You're not wrong. God, you're not wrong. It's just... Okay, so here's the thing that's really messing with me. I'm sitting here in my uncle's laundromat, at 11 o'clock on a Sunday night, with a warm beer, and I'm realizing I'm more hurt about Michelle than I ever was about David. Like the divorce sucked, but I saw that coming for a while, you know? We've been going through the motions for like two years.
|
||||||
|
|
||||||
|
LUKE: Yeah, that's a hard thing. I understand. And, you know, you've got that much history with somebody. It sucks to lose it, but it's, uh, it sounds like it's not you that has made this decision. And this person isn't somebody that's got your back that you can trust. So if you thought you had a great friend, maybe you did it once, but people change. And it sounds like she changed. And maybe some day she'll change again. But for now, let that chick go. She sucks.
|
||||||
|
|
||||||
|
TERRY: Yeah. Yeah. Yeah. She does suck. You know what the worst part is? I called her first when I found out David was seeing someone. Like two weeks ago, I saw his truck at the Applebee's with some woman, and I was all worked up about it, called Michelle literally crying in the parking lot. And she was like, oh, honey, you got to let him go. He's moved on. The whole time knowing it was her. That's that sociopath behavior, right?
|
||||||
|
|
||||||
|
LUKE: It sure is. And it's not what you would expect about a friend of 30 years. So my advice to you is just stop talking to that chick. Let her go. Let her have the dude. And, uh, move on with your life.
|
||||||
|
|
||||||
|
TERRY: You're right. I know you're right. It's just, God. It's pathetic, but I'm sitting here thinking about who I'm going to call now when stuff goes wrong. You know, like she was that person.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like you're going to call Luke at the Roost, the, uh, call in radio show where we help you out with your real world problems.
|
||||||
|
|
||||||
|
TERRY: Ha. Yeah. Well, you're doing better than she did tonight. That's for sure. I just... Okay. Real talk, though. Am I crazy for still being hurt about David?
|
||||||
|
|
||||||
|
LUKE: No, you're not crazy.
|
||||||
|
|
||||||
|
LUKE: You're hurt when you're hurt, and you've got good reason to be hurt here, and you've got some grief going on, and it's big life changes, and there's lots of reasons to be hurt. But you don't have to continue to stay that way. If you don't want to, you can decide to not be hurt and move on. And I think that's what you need to. to do. It's easier said than done, but it can be done. So just every day, wake up and be grateful to be here and say, hey, you know, I don't have the life that I had yesterday, but I've got the life that I have today, and it can still be pretty fucking cool.
|
||||||
|
|
||||||
|
TERRY: You know what? You're right. And honestly, and this is going to sound terrible. But I think I've been more hung up on the idea of David than actual David for a while now. Like we got married at 23, Luke. 23.
|
||||||
|
|
||||||
|
LUKE: Yep, that happens. That is young, and it explains a lot. So, um, you know, I wish you the best of luck. We're going to move on on the show now, unless you have some other point to bring up. I'll give you one more chance to respond. But otherwise, I'm going to say, uh, let go with the chick, let go to the dude, move on with your life, and everything's going to be fine.
|
||||||
|
|
||||||
|
TERRY: No, you're good. I appreciate you letting me vent. And hey, I heard Roland, earlier? The UPS guy?
|
||||||
|
|
||||||
|
LUKE: Yeah, what about him?
|
||||||
|
|
||||||
|
TERRY: You got a job for Roland? No, but his wife definitely sucks too. That whole thing about her wanting him out of the house? Come on. That man needs to check the credit card statements.
|
||||||
|
|
||||||
|
LUKE: That is absolutely true. I didn't want to say that to him at the time, but he absolutely should check the credit card statements. And maybe the little internal camera that he's got in the fucking teddy bear And now, now folks, you know what? Actually, she's already gone, but Terry, that was the smartest thing you sent that whole call. All right. Now it's time for a word from our sponsors. I'm not saying that for sympathy. I'm saying it because Pillow Forever asked me to establish a before state, and that's mine. Pillow Forever is a memory foam pillow that remembers your head shapes so you don't have to. It's got cooling gel, bamboo fiber, and a 30-night risk-free trial, which means you can sleep on it for a month and then send it back, and someone in a warehouse has to deal with that. Every pillow forever comes to. in a box that's too small, which is part of the experience. You open it and it slowly expands like a major documentary. My dog tried to fight it. Pillow Forever. You deserve better than a horse blanket. Okay, thanks to Pillow Forever. They are a proud sponsor of the Luke at the Roo Show, and we appreciate them. Now let's get to, uh, let's get back to the phones. Chester, Chester, welcome to the show. What's on your mind, sir?
|
||||||
|
|
||||||
|
CHESTER: Luke, hey, so I almost killed my kid this morning. Not on purpose, I mean. I didn't. I showed up to get her from her ex-wife's place, custody Sunday, and the second I rolled down the window, I could smell the whiskey coming off me. Hands still shaking. I'd been drinking until like four in the morning, and it was eight o'clock. And I'm sitting there with the engine running, thinking, well, I'm sitting there with the engine running, thinking, well, What the hell am I doing? She's seven. Her name's Daisy.
|
||||||
|
|
||||||
|
LUKE: Oh man, yeah. You can't, you can't do that, man. If you've got a drinking problem, then you're going to have to take, you're going to have to take care of that because you could kill your kid and or you could kill someone else's kid and it's really not okay. It's, it's irresponsible and it's not good for anybody.
|
||||||
|
|
||||||
|
CHESTER: No, you're right. You're absolutely right. I didn't drive. I mean, I sat there for maybe 30 seconds. And then I shut the truck off and I called her mom and told her I was sick, food poisoning or something, which is bullshit. She probably knew.
|
||||||
|
|
||||||
|
LUKE: How long have you known you've had a problem with the drinking?
|
||||||
|
|
||||||
|
CHESTER: I mean, that's the thing, Luke. I don't drink every day. I work at Desert Star Pond, been there six years. I show up on time. I do my job. It's just when I get home and Daisy's not there. When it's those empty nights, I'll start with one beer. And then it's three I'm watching Civil War documentaries with a bottle of Jim Beam. And I can tell you the exact date of Antietam, but I can't tell you when it got like this.
|
||||||
|
|
||||||
|
LUKE: Well, are you, uh, are you tired of it yet? Or it sounds like maybe this is a moment of clarity where you're recognizing the situation and, and thinking about taking accountability for it. Is that true?
|
||||||
|
|
||||||
|
CHESTER: Yeah. Yeah. Yeah. I think. I mean, my dad, Big Jim, he ran cattle for years. Never missed a day. Never touched the stuff.
|
||||||
|
|
||||||
|
LUKE: Well, you know, they have support group meetings. It can help you out in these situations. You can go to after work. Lots of cool people there that are trying to live sober, not pick up the drink and end up in situations like you're finding yourself in now. It is possible. You don't have to get drunk by yourself at night watching Civil War documentaries. You can just watch the Civil War documentary without they're getting drunk bit. then when you get up in the morning and pick up your kid, you're not going to be drunk.
|
||||||
|
|
||||||
|
CHESTER: I know. You're right. It's just, the house is so damn quiet, you know? And I keep thinking about what kind of example I'm setting.
|
||||||
|
|
||||||
|
LUKE: Well, it's good that you figure it out now when you're at a spot where you can still do something about it. And what I recommend is when you get home, next time you get home, do something else. Instead of cracking that beer, just do anything else. You can play a video game or you could, uh, go for a walk or you could read or play on the internet, whatever it is, just break that habit of having that first beer. Because if you don't pick up the first one, you're not going to end up drunk. Isn't it funny how that works? If you don't pick up the first one, you're not going to end up drunk.
|
||||||
|
|
||||||
|
CHESTER: Yeah, yeah, that makes sense. I heard Lori earlier, the trucker lady with the daughter sneaking out, and I kept thinking at least she's got a reason she's not around, you know?
|
||||||
|
|
||||||
|
LUKE: No, what do you mean by that?
|
||||||
|
|
||||||
|
CHESTER: I mean, she's working. She's on the road providing for her kid. Me, I'm just, I'm home and Daisy's at her moms. And I'm choosing to sit there with a bottle instead of, I don't know, calling her reading her a bedtime story over the phone. Something.
|
||||||
|
|
||||||
|
LUKE: Well, yeah. And, uh, you know, sometimes you just have to say that to a radio host at midnight to, uh, to hear yourself say it. So hopefully you can snap out of your, uh, your, your situation. Don't pick up the beer next time. And instead, call your daughter and read her a story.
|
||||||
|
|
||||||
|
CHESTER: You're right. I actually. I got this book about Gettysburg I was going to show her. She's been asking about it because we drove through Pennsylvania last summer. And she saw the signs. Smart kid. Smarter than me, that's for sure.
|
||||||
|
|
||||||
|
LUKE: Well, you sound pretty smart today. You know you get a problem and you're going to do stuff to take care of it. So if you need help, then I recommend that you find your your local neighborhood at AA or NA meetings, depending on what type of situation you're dealing with. And just go check it out. And have an open mind and maybe you find a new way of life. Okay, Dolores. Delores, welcome to the radio show. How can we help?
|
||||||
|
|
||||||
|
DELORES: Hey, Luke. Yeah. So, okay. I got recognized today at an open house and I kind of panicked. And now sitting in a circle K parking lot feeling like a complete idiot.
|
||||||
|
|
||||||
|
LUKE: Well, all of us get recognized several times a day. So why is it, what is it about this particular recognition that's got you up in arms?
|
||||||
|
|
||||||
|
DELORES: Because I've been going to open houses every weekend for like eight months and I'm not actually buying anything. This realtor, Patricia, she remembered me from a showing last spring, and she just asked me you actually planning to buy a house and I froze. I told her my financing fell through, but that's not even true because I've never applied for a loan in the first place.
|
||||||
|
|
||||||
|
LUKE: Okay. Next up on the radio show, we have Marvin. Marvin, thanks for calling in. What's happening tonight?
|
||||||
|
|
||||||
|
MARVIN: Hey, Luke. Yeah, thanks for taking the call. So I got home for my shift tonight and there's this cardboard box sitting on my porch. No note, nothing. And it's full of stuff from my dad's house. Stuff I haven't seen since he died 11 years ago. His Bolo tie. This pocket knife I thought I lost senior year. Photos of my uncle's old place.
|
||||||
|
|
||||||
|
LUKE: What's a Bolo tie?
|
||||||
|
|
||||||
|
MARVIN: Oh, it's that Western Thai thing. You know, the braided leather cord with the silver clasp that slides up and down. My dad wore one to every wedding, every funeral, every time he needed to look respectable. His had this. This turquoise stone in the middle, real heavy.
|
||||||
|
|
||||||
|
LUKE: Okay, well, that's cool. Somebody dropped off some of your dead dad's belongings, and what are they bringing up inside? They bring it up memories? Is this got you upset? Are you concerned? Like, what's, what feeling is this bringing up inside of you?
|
||||||
|
|
||||||
|
MARVIN: I mean, yeah, memories. But more than that, I'm sitting here like, who the hell had this stuff? my dad's been gone 11 years. Where has this box been? And why now? Why tonight? What's in the box? Why no explanation? Like, someone just decided, oh, time for Marvin to deal with this and left it there like a package from Amazon. And honestly, I opened it and just...
|
||||||
|
|
||||||
|
LUKE: All right. Well, congratulations for, uh, the... safe return of your dad's belongings. I hope that you wear them in good health. Next on the radio show, oh, before, no, oh, Luke, you almost, come on, come on, I'm fucking amateur here. It is time for a word from our sponsors. Look, I'm not a financial advisor. I'm a guy with a microphone and a dog. But the folks at Crypto know asked me to tell you about their new decentralized investment platform, and I to read this part. Past performance does not guarantee future results. This is not financial advice. And if you invest your rent money, you deserve exactly what happens next. Crypto No lets you trade over 400 digital currencies, including three that were invented this morning, and one that's just a picture of my dog. The app features a real-time portfolio tracker with a built-in panic button that just plays ocean sounds when your balance drops. Crypto No! Fortune favors the bold, but it does not return their calls. Okay, thanks to Crypto No for sponsoring the show today. I think we're probably running a little bit late. These have been some decent calls. They're going a little long. So I'm just going to take one more for tonight's show. And next up to the line, we have Francine. Francine, you're going to be our last caller of the night.
|
||||||
|
|
||||||
|
LUKE: What's on your mind?
|
||||||
|
|
||||||
|
CALLER: Luke, I just had a deer on the 11, and it's still alive, and I don't know what the hell I'm playing. supposed to do about it. I've been sitting here with my hazards on for like 20 minutes. Just, it's looking at me. When if its legs is completely shattered, it's on the shoulder. And I can't tell if I'm supposed to call someone, or if I'm supposed to, I don't know, put it out of its misery myself? Which I don't even know how I do that. I'm a nurse. I work on people, not my ex would have known. He grew up out here, hunted with his dad. He would have just handled it.
|
||||||
|
|
||||||
|
LUKE: Yeah, that sounds like a. less than ideal situation. I would call the police first, call 911, and let them know that there's been an accident and there's an animal, I assume, still in the road. If you have a gun, then I think you know what you have to do. If you don't have a gun, I would probably refrain from doing anything hasty with like a tire iron or a rock.
|
||||||
|
|
||||||
|
CALLER: No, I don't have a gun. It's off the road. It's on the shoulder. So nobody's going to hit it. I just, I'll call. I didn't know if this was even a 911 thing or if there was like animal control or something, but out here at midnight on a Sunday, I guess there's not exactly a whole directory of options. The stupid thing is, I've been driving the same loop between Deming and Los Cruces for six months now. Three different clinics, and this is the first time I've hit anything.
|
||||||
|
|
||||||
|
LUKE: Well, you know what I always say? 911 was an inside job. So I don't actually know who you're supposed to call in this situation. I would call 911 and ask the them and they'll let you know or send out animal control or whoever comes out of the sheriff's office. Who knows out here especially? But, you know, it happens. There's wild animals out here. They run in the road. Sometimes we hit them. It's probably not your fault unless you were playing with your phone, and in which case it was your fault. And just do the best you can do. It's unfortunate that the animal's suffering right now, but if you don't have a way to humanely end it, then you got to just get somebody out there as soon. as you can.
|
||||||
|
|
||||||
|
CALLER: I wasn't on my phone. I was just tired. Just came off a double. Wasn't paying attention like I should have been. You're right, though. I'll call.
|
||||||
|
|
||||||
|
LUKE: All right. Well, get off the line with me and get on the line with 911. And that is the conclusion of our show for tonight. Thanks everybody for tuning in, and we'll talk to you again tomorrow. Thank you.
|
||||||
@@ -0,0 +1,397 @@
|
|||||||
|
LUKE: All right, welcome back to the show. My name is Luke. I'm your host for Luke at the Roost. This is the radio show where we take callers and give them the best advice that we can. If you'd like to call into the show, the number is 208-439-5853. That's 208-439 Luke. Also, new just yesterday. If you can't get to a phone and you'd like to participate in the show, you can send us an email. The address is submissions at Lukeat the roost.com. Submissions at Luke at theroost.com. So you can send us a question or a story or anything you want. And if it's funny enough, I might read it on the air in the next show. And if it's not me, maybe I'll have one of my robot friends read it for me because I'm lazy. All right. So today is Monday, February 16th. It's about 11.30 p.m. And our phones are lighting up like they always do at this time of night. the show, we have Hector. Hector, welcome to the show. Thanks for calling in. How are you doing out there tonight?
|
||||||
|
|
||||||
|
HECTOR: Hey, Luke. Doing all right, man. Doing all right. Appreciate you taking the call. So listen. I got myself into a situation here, and I don't know whether to laugh or start updating my resume.
|
||||||
|
|
||||||
|
LUKE: All right, Hector. What did you do?
|
||||||
|
|
||||||
|
HECTOR: So I've been flying crop dusters out of Yuma for eight years now, right? Good job. Decent money? I know what I'm doing up there. This afternoon, my boss pulls me aside. All smiles tells me I landed this huge contract in Mexico City. Three weeks coordinated with agricultural officials. Big deal for the company.
|
||||||
|
|
||||||
|
LUKE: Is that something you don't want to do? Why you bummed out about that? That sounds great.
|
||||||
|
|
||||||
|
HECTOR: No, no, that's the thing. It should be great, right? This is a promotion, basically. More money, more responsibility. Looks amazing on paper. Here's the problem, Luke. hired me eight years ago partly because my last name is Gonzales and my resume says fluent Spanish I speak about as much Spanish as you probably do maybe less
|
||||||
|
|
||||||
|
LUKE: I'm gonna let you in on a little secret I think they knew they probably had strong suspicions at the time they hired you that you did not speak Spanish but that's okay because nowadays you don't have to you can get the Apple AirPods and they'll do the live translation for you right in your ear
|
||||||
|
|
||||||
|
HECTOR: Oh man, I didn't even think about that. Does that actually work, though? Like in a real professional setting? Because I'm picturing myself in some meeting with Mexican agriculture officials, trying to negotiate pesticide schedules, while I'm sitting there with AirPods and like I'm listening to a podcast.
|
||||||
|
|
||||||
|
LUKE: You know, I went into Mexico last year at some point. I went to Agua Brietta. And when I got there, I was trying to buy cigarettes from the duty-free shop on the United States side of the border. So they don't just give you the cigarettes. You buy the cigarettes in the United States, and then you have to cross the border, and some guy is supposed to bring you the cigarettes, and then you have to import them back into the United States. So I went out there, and I was in Mexico, and I couldn't find the guy with the cigarettes. So I'm asking all around, and there's a bunch of, like, their version of Border Patrol at the border, and they didn't speak any English or pretended not to speak any English, and they pulled out their phone, and they just did the whole back-and-forth transcription, like it was nothing. Like, they do that all the time. So I think it's pretty common. I wouldn't worry too much about it. But you can always start studying. I mean, it's not like you can't learn Spanish.
|
||||||
|
|
||||||
|
HECTOR: Yeah, I mean, three weeks, though. I've been downloading Duolingo on and off for like two years, and I still can't get past the boy eats an apple. And here's the other thing that's dealing at me. I've been cashing paychecks for eight years with that my resume like they never needed me to speak Spanish before so it never mattered but now it does and I feel like a fraud
|
||||||
|
|
||||||
|
LUKE: well you are a fraud you lied on your resume and you got away with it for eight years so congratulations for that but it sounds like it's probably pretty difficult to find somebody qualified to fly crop dusting plane that they trust in another country and they trust you so you just got to do the best you can and try to work through the Spanish you know Three weeks, that's quick, but you can do it. I mean, dual lingo is probably not the right way, but there's lots of other ways to learn language, and if you really need to, if you really have to, you could get at least a little bit of what you need. It shouldn't take you long to ramp up.
|
||||||
|
|
||||||
|
HECTOR: You're right, you're right. I mean, I've been hearing Spanish on the radio stations down here for years. I should at least have some baseline. And honestly, the flying part I can do in my sleep, what's got me twisted up.
|
||||||
|
|
||||||
|
LUKE: Just throw yourself on a Selena record, get some bitty bitty bum bomb going, and you're gonna be fine. Amherst yourself in Spanish, and you will pick it up faster than you think, because you have to.
|
||||||
|
|
||||||
|
HECTOR: Okay, Selina, I can actually handle. My mom used to play that stuff all the time when I was a kid.
|
||||||
|
|
||||||
|
LUKE: You can't handle Selena. Wait, does that make it worse, that I didn't pick up Spanish?
|
||||||
|
|
||||||
|
HECTOR: She's probably going to lose it when I tell her about this. She's been asking me for years why I don't speak it and I always just shrugged it off.
|
||||||
|
|
||||||
|
LUKE: Well, your name is Hector Gonzales, so I mean I would expect at this point in your life you probably would have picked up a little bit here and there.
|
||||||
|
|
||||||
|
HECTOR: That's what kills me, Luke. Everyone just assumes. I walk into a place, they see the name tag, and half the time someone starts talking to me in Spanish, and I just stand there like a deer in headlights. I've gotten really good at the apologetic smile and the sorry I don't speak it. But my dad's of the family, they all came over generations ago. By the time it got to me, it was just gone.
|
||||||
|
|
||||||
|
LUKE: Hey, well, congratulations on the new job. Do the best you can. And if they have to send you back to the States to do your old job again, then so be it. And if they fire you for lying on your resume, then get another job. There's probably plenty of places you can commercially fly a plane.
|
||||||
|
|
||||||
|
HECTOR: Yeah, you know what? You're right. Worst case scenario, I'm back flying over lettuce fields and Yuma, which honestly isn't the worst thing in the world. I do love that job.
|
||||||
|
|
||||||
|
LUKE: Well, good luck to you and congratulations again. Thanks for calling in, Hector, and give us a call back if anything goes wrong or you meet a crazy cartel out there and you've got a story about redemption. Next up on the line we have Marlene. Marlene, welcome to the show. What's going on in your life tonight? How can we help?
|
||||||
|
|
||||||
|
MARLENE: Hey, Luke. Yeah. So, My ex-wife's new husband just ordered $12,000 worth of furniture for me, and I don't know if he knows it's me or not, and I'm losing my mind a little bit. Sorry, that came out fast. But yeah, that's what's happening right now.
|
||||||
|
|
||||||
|
LUKE: Well, you know, all the places in the world you could buy furniture from, if he's buying it from you, then there's a good chance he has an idea of who you are. Right?
|
||||||
|
|
||||||
|
MARLENE: That's what I keep thinking. the company's called Desert Reclaim and my name's all over the website. But then I'm like, maybe he just Googled Rustic Dining Tables, New Mexico. And I came up and he has no clue. He's this tech guy from Scottsdale, you know?
|
||||||
|
|
||||||
|
LUKE: Yeah, well, I mean, you got to think about how internet search works and cookies and stuff like that. So there's probably a chance that she was looking at your Facebook profile and somewhere you're linked to your business profile on LinkedIn or something like that. And then that's a chance that's transferring to his phone, so when he does a Google search, it's looking at all that data it's collected on you, and saying he's most likely to buy his chairs from this woman.
|
||||||
|
|
||||||
|
MARLENE: Oh, God, I didn't even think about that. So, like, Rachel's been looking at my stuff and it's bleeding over into his search results. That's, actually, that makes me feel weird in a whole different way.
|
||||||
|
|
||||||
|
LUKE: Like, has she been checking up on me? Well, I don't know. I'm just saying that's one possibility. That is how search works nowadays. So there's a likelihood that that could have happened. And not necessarily like Googling you in the middle of the night, but there could be documents on our computer that are getting fed into the cloud for some PDF transcription service. Like, you don't know. All that you know is the data is out there and you're linked to him now in a not a cryptographic way, but in a digital way. And that link is obviously working.
|
||||||
|
|
||||||
|
MARLENE: Yeah. No, you're right. I mean, we were married for six years. probably all kinds of digital trails still connecting us. But, okay, so whether he knows or not, do I take the money?
|
||||||
|
|
||||||
|
LUKE: Yes! Luke, this is six months of my mortgage. This order would let me actually breathe for the first time since I started this business.
|
||||||
|
|
||||||
|
MARLENE: But then I think about Rachel walking into one of those hotel lobbies and seeing my tables, the ones I built with wood from that barn outside animas, and I just...
|
||||||
|
|
||||||
|
LUKE: Not your problem. Take the money. Congratulations. That's a good hit. That's what we call us in the business. So close that deal, take your cash, and enjoy the win. And thank modern technology.
|
||||||
|
|
||||||
|
MARLENE: You really think so? Just take it and don't say anything? Because part of me wants to email him and be like, Hey, just so you know, I used to be married to your wife. Is that insane? That's insane, right?
|
||||||
|
|
||||||
|
LUKE: You are correct. That is insane. Yeah, don't do that. Take the money and don't say a word. And who cares if she looks at York when she goes to wherever it is, she goes where they put your furniture.
|
||||||
|
|
||||||
|
MARLENE: Okay. Yeah. You're right. I mean, she left me. She married him. I'm building furniture in my garage at two in the morning. This is literally the one good thing that's happened.
|
||||||
|
|
||||||
|
LUKE: Nah, she got to be with somebody she wants to be with. You get to make maybe potentially the best work of your life. And you just got a nice paycheck. So it sounds like there's lots of good things happening. And all around, everything works out the way it's supposed to. And enjoy this small win.
|
||||||
|
|
||||||
|
MARLENE: Small win? Luke, this is 12 tables. This is the biggest order I've ever had. But, okay. Yeah, I hear you. Take the money, build the tables, stop overthinking it. It's just, man, it's been a year of sleeping in my truck, watching the stars, trying to figure out what I'm doing. And now this lands in my lap and it's connected to her. And I just...
|
||||||
|
|
||||||
|
LUKE: You're just freaking out. And you don't have to freak out. Do the job, get the money and move on and enjoy it. Congratulations.
|
||||||
|
|
||||||
|
MARLENE: You know what? You're right. I'm going to do it. I'm going to build the best damn tables they've ever seen, take their money, and maybe finally fix the heater in my truck, so I don't have to freeze my ass off out there.
|
||||||
|
|
||||||
|
LUKE: Excellent. That sounds like a great plan. And another happy rooster. It's time to hear from our sponsors. So in just a moment, we'll return.
|
||||||
|
|
||||||
|
I'm going to be straight with you. I don't know what this product does. The folks at Bunkhouse DNS sent me a script and I've read it four times and I understand maybe 11% of it. Apparently your DNS is exposed, which sounds medical. Your queries are being logged by default, which sounds illegal. And Bunkhouse reroutes your lookups through encrypted tunnels, which sounds like something a villain would say in a movie before the building explodes. What I can't really tell you is this. I installed it. I pressed one button and a little shield icon turned green. Green means good. I know that much. My internet still works. Nothing exploded. And apparently my queries, whatever those are, are now private, which feels like progress, even though I don't fully understand progress from what? Bunkhouse DNS. I don't know what it does, but the shield is green, and that's enough for me.
|
||||||
|
|
||||||
|
Okay. Welcome back to the show. Just a quick plug. Don't forget, we have presents out there on all the social media. So you can find us on the Facebook and the Instagram and the YouTube's and the Apples and the Spotify's all around. If you want to look at all the places you can find us, look at Lukeattheroast.com. And with that out of the way, let's get back to the show. Rick, Rick, thanks for calling in. What's going on, buddy?
|
||||||
|
|
||||||
|
RICK: Oh man, Luke. So yesterday morning, my daughter Claire, she's 12. She fell through the on our stock tank trying to break it up for the horses, right? Full face pallant into freezing water, and I'm watching this happen, and I'm about to lose my mind. But she comes up and she's gasping, but she's not panicking, like it all. And later she tells me, it felt like her body just...
|
||||||
|
|
||||||
|
LUKE: Her body just what?
|
||||||
|
|
||||||
|
RICK: Took over. That's exactly what she said. My body took over. Like she wasn't even in control. Her heart slowed down, blood went to her core, and she just knew what to do. So I'm sitting there after she goes to bed and I'm looking this up. And Luke, it's called the mammalian diving reflex.
|
||||||
|
|
||||||
|
LUKE: Well, that's pretty helpful, I suppose. Uh, I, for if we like jump into the ocean when it's cold, like, uh, why is it there?
|
||||||
|
|
||||||
|
RICK: Right, exactly. It's this ancient thing we all have, like seals and whales. Your face hits cold water and boom, your body just flips this switch without asking permission. Heart rate drops, blood vessels constrict, everything shut down except what keeps you alive.
|
||||||
|
|
||||||
|
LUKE: Well, that sounds like a very handy thing to have, especially if you're going to fall into a trough of water when it's frozen.
|
||||||
|
|
||||||
|
RICK: Yeah, no. I mean, she's fine. She's totally fine. But Luke, here's the thing that's messing with me. I've known this kid her whole life, right? Change to diapers, taught her to ride, the whole deal.
|
||||||
|
|
||||||
|
LUKE: Okay. And what's the problem? It sounds like she's perfectly fine, and you learned a new thing about biology and evolution.
|
||||||
|
|
||||||
|
RICK: The problem is, I watch her face in that water. And it was like, I don't know her at all. Like there's this whole other operating system running underneath that I have zero access to. She's got the same emergency programming as a seal, Luke, a seal.
|
||||||
|
|
||||||
|
LUKE: I've been kissed by rose on the grave. Yeah, I guess that would be startling. But wait a few more years until you see her get hammered. And then, uh, see what you see in her face.
|
||||||
|
|
||||||
|
RICK: Oh, God. Don't even. No, but see, that's different. That's like choices and stupid decisions. This wasn't a choice. This was her body making calls without her even knowing. Like she's running software I didn't install and can't see the code for.
|
||||||
|
|
||||||
|
LUKE: Yeah, and it sounds like it's doing a better job than yours too, because she acted superfluously and got herself out of that cold water before it was an issue. So what's the problem here? Her natural biology was taken over and doing the right thing.
|
||||||
|
|
||||||
|
RICK: The problem? Okay. You're right. She handled it better than I would have. But Luke, she's 12. And I'm standing there on a Monday morning watching Evolution work through my kid like she's just...
|
||||||
|
|
||||||
|
LUKE: Yeah, you watched Evolution the whole, every day of watching that kid grow up, and all of you growing up and all your parents. So I'm not sure why this is flipping your wig.
|
||||||
|
|
||||||
|
RICK: Because this wasn't her getting taller or losing teeth or whatever. This was watching her go under and come back up with this look on her face like, Like some part of her I've never met, just took the wheel. She told me later, my body took over dad, and I can't stop thinking about what else is in there that I don't know about.
|
||||||
|
|
||||||
|
LUKE: I've been kissed by Rose on the grave. Do you think seal is in there?
|
||||||
|
|
||||||
|
RICK: What? No, I.! Luke, come on. I'm not saying she's literally a seal. I'm saying she's got all this programming I didn't know about. Like, what else kicks in that I'm not ready for? What other switch is flea when I'm not looking.
|
||||||
|
|
||||||
|
LUKE: I don't know, man. It sounds like you're going to have to read the origin of species and do some research on the old Charlie D.
|
||||||
|
|
||||||
|
RICK: Okay, you're busting my balls here, but I did look it up after she went to bed. The mammalian diving reflex. It's real.
|
||||||
|
|
||||||
|
LUKE: Heart rate drops. Blood goes to the vital organs, the whole thing. And she described it exactly like that without knowing what it was called. That's what's freaking me out. She's walking around with all these systems I can't see. And one day she's going to be out there making decisions. and I won't even know what's running in the background.
|
||||||
|
|
||||||
|
RICK: Yeah, that's true. That's how humans behave. Welcome to the world, sir. You don't know how anybody is programmed entirely, and just the little bits that you've been around for. So it's not to be shocking, but it sounds like you need to expand your mind a little bit. Your kid is going to be their own person with their own instincts and values and beliefs and skills. And most of them. them, not all, most of them will have absolutely nothing to do with you.
|
||||||
|
|
||||||
|
LUKE: Yeah, yeah, I know that. I do, but this felt different. Watching her face change in that water, watching something ancient, just click on.
|
||||||
|
|
||||||
|
RICK: Well, it sounds like everything worked out, and she's great, and you learned something, and that's a win to me.
|
||||||
|
|
||||||
|
LUKE: So thanks for Colin. Give us a call back some other time. Gina, Gina, thanks for Colin. How are you today?
|
||||||
|
|
||||||
|
GINA: Hey, Luke. I'm all right. So my brother and sister want to sell my grandmother's house, and I've been breaking into it every Sunday for the last three months.
|
||||||
|
|
||||||
|
LUKE: Is your grandmother still in the house?
|
||||||
|
|
||||||
|
GINA: No. She died in November. I have a key, though, so I guess it's not really breaking in. But they don't know I'm going there.
|
||||||
|
|
||||||
|
LUKE: Okay, why are you breaking into your dead grandma's house?
|
||||||
|
|
||||||
|
GINA: I don't know, man. I just, I drive down to Hachita every Sunday, let myself in, and I sit in her chair by the window for exactly two hours. Sometimes I'm on my phone. Sometimes I just watch the mountains. It's this floral armchair she'd always sit in.
|
||||||
|
|
||||||
|
LUKE: Well, that's a nice thing, but if they're going to sell the house, you're not going to be able to go there anymore. So that's a bummer. What are you going to do after the house is gone?
|
||||||
|
|
||||||
|
GINA: That's the thing. I don't want them to sell it. My brother left me three voicemails saying we need to list it by March. And my sister sent me the Zillow estimate and I had to pull over on the highway because I couldn't breathe. Like, I know how this sounds.
|
||||||
|
|
||||||
|
LUKE: Do you have the money to buy the house?
|
||||||
|
|
||||||
|
GINA: No. I work at a mortuary. I'm 21. I don't have that kind of money. But I can't explain this to them without sounding crazy.
|
||||||
|
|
||||||
|
LUKE: Well, you're 21. You also don't have the bills yet that they have, and the responsibilities financially that they have to account for. You don't have to pay the taxes on that property and the upkeep and the maintenance. You're just going there and hanging out, which is great. I mean, if you've got a free place to go hang out, wonderful. But the rest of your family, doesn't feel that way about it. It's a burden to them, and it's expensive, and they might not be able to afford it either. So if they want to sell the house, then you should let them.
|
||||||
|
|
||||||
|
GINA: I know all that. I get it. But she's still in there, Luke. And I know the difference between a body and a person. I work with dead people every day.
|
||||||
|
|
||||||
|
LUKE: Okay. Well, so if she's still in there, does it matter who owns her?
|
||||||
|
|
||||||
|
GINA: What do you mean does it matter who owns her? Some family from Phoenix is going to buy it and go. that the whole thing and turn it into an Airbnb or whatever.
|
||||||
|
|
||||||
|
LUKE: Yeah, and that sounds like an ideal situation for your dead grandma, because she's going to be hanging out in the Airbnb, it's going to be all nice and fixed up, and people are going to be partying in there, she's going to be having a grand old time.
|
||||||
|
|
||||||
|
GINA: That's not funny.
|
||||||
|
|
||||||
|
LUKE: What do you mean it's not funny? Of course it is.
|
||||||
|
|
||||||
|
GINA: No, because, okay, you don't get it. Every Sunday I sit in her chair by the window and I can feel her there. feel her. The way the light hits the mountains at a certain time, that's what she looked at every day for 40 years. Her handwriting is still on the grocery list on the fridge. There's a water stain on the ceiling from when the swap cooler leaked in 2019. And she never fixed it because she said it looked like a bird.
|
||||||
|
|
||||||
|
LUKE: Yeah, it sounds like she was a person and she is not anymore. And her house is no longer belongs to her and you're in it hanging out. And the family needs to sell that house, whether you want to be there or not. Like, you can't just force them to keep this house. You can't do it. It's not going to work. So you're going to have to come to terms with reality.
|
||||||
|
|
||||||
|
GINA: I know I can't force them. That's why I'm calling you instead of just, I don't know what I thought you were going to say.
|
||||||
|
|
||||||
|
LUKE: Well, what I'm going to say is it makes sense that you're grieving for your grandmother. And her presence is obviously. going to be in the place where she lived her whole life. That makes perfect sense. That happens to everybody. I'm going to tell you that you can take those memories of your grandma somewhere else, and you're going to have to. So it's okay to grieve. It's okay to miss her, but she's not in the walls. She's not in the stain on the ceiling. She will follow you for your life in your mind, in your memories, and keep those good, you know? And if you really, if you really, if you really feel that strongly about it? Do what you have to do to raise the money to buy the house. Like it's an after-TV special, and there's some creepy old corporation that's trying to buy it and turn it into an oil drill.
|
||||||
|
|
||||||
|
GINA: I make $22 an hour at the mortuary, Luke. My brother's a project manager in Tucson, and my sister works for the state. They've already run the numbers. If we sell now, we each get like $40,000. That's real money for them. That's their kids' college funds or whatever. And I can't explain to them why it matters without sounding insane.
|
||||||
|
|
||||||
|
LUKE: It doesn't sound insane. It sounds selfish. Because it's not yours to hold on to. So if you make $22 an hour at the mortuary, that's not a lot of money, but you could go make more money. You could have a second job, a third job. You could make deals with people, talk to the bank. $40,000 is not that much money, and you could raise it if you really wanted to. You can do a GoFundMe. I mean, you can crowdsource a lot of money. You can borrow a lot of money. You could make it happen, but, I mean, it goes back to you. And this would be something that you have to do. It's not something that you're forcing those other people that are in real world responsible situations. You can't be upset with them for doing what they need to do.
|
||||||
|
|
||||||
|
GINA: You're right. God, you're right, and I hate it. I've been sitting there every Sunday like I'm keeping her alive or something. Like if I'm keeping her alive or something. I just stay in that chair long enough. It won't matter that she's gone. But I work with dead people every day, Luke. I know better. I'd prep buddies.
|
||||||
|
|
||||||
|
LUKE: Well, if you know better, then snap out of it, because she is gone, and she's not in the house, and it's not your house.
|
||||||
|
|
||||||
|
GINA: Yeah. Okay. Yeah. You're right. I just, I have to figure out what to say to my brother, because he's been really patient, and I've been dodging his calls for two weeks. I can't keep doing that.
|
||||||
|
|
||||||
|
LUKE: Well, figure out what you're going to say to your brother, and make peace with what you've got to make with or go get yourself the money.
|
||||||
|
|
||||||
|
GINA: I'm not getting the money. I know that. I think I knew that when I called.
|
||||||
|
|
||||||
|
LUKE: Okay, you're not getting the money. Well, good luck to you, you little bitch. Jesus. I don't know. What generation is that? She said she was 21. Is that Gen. A, Gen. Gen. I don't know what gender. She sucked. Okay. Let's see. Skeeter. Welcome to the show. What did you think of that last caller?
|
||||||
|
|
||||||
|
SKEETER: I thought she was super annoying. Oh man, I missed it actually. I've been sitting out here in the parking lot with the heat running, just got the station dialed in. But listen, I got a question that's been eating at me all day.
|
||||||
|
|
||||||
|
LUKE: You know that thing about how orange used to be called yellow red? Like before the word orange existed, people just called it yellow red? I did not know that, and that sounds odd. It sounds untrue.
|
||||||
|
|
||||||
|
GIO: See, that's what this kid in my sense. seventh period said, called it bullshit internet fake history, right to my face, which, you know, fair enough, I let them talk like that in my class, as long as they're making a point.
|
||||||
|
|
||||||
|
LUKE: And did you have anything to back this up with?
|
||||||
|
|
||||||
|
GIO: That's the thing. I don't know, man. I saw it somewhere online, but it was interesting, been telling people for like two years. And now I'm sitting out here at midnight, second-guessing, whether I actually know anything real, or if my whole brain is just filled with internet garbage, Like, what else have I been confidently wrong about? You know what I mean?
|
||||||
|
|
||||||
|
LUKE: Well, have you taken any steps to verify the information? Like maybe Google it, look it up?
|
||||||
|
|
||||||
|
GIO: Yeah. I did that after class, and it just made it worse. Half the sites say it's true, half say it's not, and I can't tell which ones are legit. There's something about the word coming from the fruit, or maybe Sanskrit. Or maybe it was Geo-Lou Reed in Old English, which I guess means yellow-red? I don't know. I teach history. and I can't even figure out the history of a color. And honestly, Luke, that's not even really why I'm calling.
|
||||||
|
|
||||||
|
LUKE: Well, Gio, Lou Reed, sounds like something I want to get behind. All right, why are you calling?
|
||||||
|
|
||||||
|
GIO: I've been sleeping in my truck in the school parking lot for three nights because my girlfriend changed the locks on me. Found some texts I sent to someone I shouldn't have been texting. And I'm sitting out here with the engine running so I don't freeze, watching the frost build up on the windshield. And I'm the exact same age. my dad was when he left.
|
||||||
|
|
||||||
|
LUKE: Okay, well, it sounds like you're getting what you deserve. So who are you texting? What was that about?
|
||||||
|
|
||||||
|
GIO: Her name's Amanda. She's a substitute teacher, comes through maybe once a month, and it wasn't even, look, nothing actually happened. It was just flirty stuff, stupid stuff, but enough that when my girlfriend saw it, she knew exactly what I was thinking about doing, even if I hadn't done it yet. And the worst part?
|
||||||
|
|
||||||
|
LUKE: What's the worst part? You know women don't like. it when you text other women.
|
||||||
|
|
||||||
|
GIO: The worst part is, I don't even feel that bad about it. Like, I know I'm supposed to be devastated, right? Begging to come back inside, flowers and apologies and all that. But mostly, I just feel nothing. I've been with Sarah for four years, and when she changed those locks, part of me was relieved.
|
||||||
|
|
||||||
|
LUKE: All right, well then, congratulations. It sounds like your decision's been made for you. You're all set. You're free, sir. You're a free bird. You're a free agent. You can text whoever you want.
|
||||||
|
|
||||||
|
GIO: Yeah, except I'm 37 years old sleeping in a Tacoma in a high school parking lot. Real winter energy, Luke. And here's the thing that's messing with me. My dad did this exact same thing. Same age? Found someone else. Just walked away from everything. I spent my whole life thinking he was a piece of shit for that, and now I'm out here doing the same math he probably did.
|
||||||
|
|
||||||
|
LUKE: Well, you're not really just walking away from everything. She changed the locks on you. She told you to leave and apparently not come back.
|
||||||
|
|
||||||
|
GIO: No, you're right, but I handed her the reason to do it. I mean, come on, Luke. I left those texts where she could find them. My phone was sitting right there on the counter while I was in the shower. I'm not stupid. Part of me wanted her to see them. Part of me wanted her to be the one to pull the trigger so I wouldn't have to.
|
||||||
|
|
||||||
|
LUKE: Okay, well then, you're a pussy, and it sounds like you've got exactly what you wanted. So congratulations. I'm not sure why you're calling me.
|
||||||
|
|
||||||
|
GIO: Because today, I told my seventh period class, that thing about how orange used to be called yellow-red. And this smart-ass kid, always correcting me, said that's fake internet bullshit. And I'm sitting out here now wondering if he's right. Wondering if I actually know anything real, or if I'm just repeating stuff I saw online at three in the morning. And that feels like, I don't know, man. It feels like everything right now. Like maybe I don't actually know what I want or what I'm doing or who I even am.
|
||||||
|
|
||||||
|
LUKE: Well, welcome to the goddamn human race, sir, because nobody really does. It's the big secret that we're all hiding and pretending, you know, telling the kids that isn't the case. Nobody fucking knows, man. Just do your best. If you don't want to be with that woman, don't be with the woman. And it sounds like you're not anymore, so good on you. Now you're going to have to find yourself a new place of residence. So I would be worried about that more so than the color orange.
|
||||||
|
|
||||||
|
GIO: You're right. You're absolutely right. I just... Okay, so earlier you had that guy Hector on, the crop duster who lied about speaking Spanish, and you told him, Worst case, he just goes back to doing what he was doing before, which he loves anyway.
|
||||||
|
|
||||||
|
LUKE: Yeah, I was talking about a job, not a woman.
|
||||||
|
|
||||||
|
GIO: I know, but that's what I'm saying. I can't go back. There's no version where I go back to what I was doing before, because I don't even remember what that was. Sarah and I got together when I was 33. Before that, I was just, I don't know, Luke. I was just floating around. And now I'm floating around again, except I'm four years older and sleeping in my truck, and I can't even confidently tell a 17-year-old kid whether Orange is a real cool. color or not.
|
||||||
|
|
||||||
|
LUKE: Yeah, you're a goddamn mess, and you need to fucking pick yourself up and get it together because, uh, this is pathetic.
|
||||||
|
|
||||||
|
GIO: Yeah, yeah, you're right. It is pathetic.
|
||||||
|
|
||||||
|
LUKE: Okay, so grow up, figure out what you want to do and stop, uh, uh, holding people hostage. Now it's time for another word from our sponsors. I'm going to get dark for a second. You're going to die someday. Not today, probably, but someday. And when you do, what's going to represent your business? A Craigslist post from 2020? A Google Maps pin that still says permanently closed because you forgot to update it after COVID. A nephew who knows computers but actually just has a Reddit account? Your legacy deserves better than a nephew with a Reddit account. Squarehole lets you build something that outlasts you, something your kids can point to and say, Dad built Dad. They won't know it took you 11 minutes. That's between you and Squarehole. And when your nephew says, I could have built that for you for free, you can look them in the eye and say, then why didn't you, Tyler? I asked you in 2021 and you said you were busy and you were not busy. Squarehole. Build it before Tyler has to, because Tyler is not going to. Tyler's not going to do it, so you should talk to our sponsor there. Get yourself a website. A website like our website, Luke at the roost.com. which is not hosted on Squarehole. It's hosted a completely different way. And if you'd like to know how it's hosted, you can take a look at Luke at theroost.com slash how it works. Or we explain how this whole show works to those of you that might be interested. Okay, next up on the line, we've got a returning caller. I remember you. This is Brenda. Brenda. Brenda, you're the ambulance driver, right?
|
||||||
|
|
||||||
|
BRENDA: Yeah, that's me. Hey, Luke. So I did it. I actually went on a date.
|
||||||
|
|
||||||
|
LUKE: Hey, all right. Good job. Good for you. How'd that go?
|
||||||
|
|
||||||
|
BRENDA: Oh, man. It was. Okay. So I met this guy at the grocery store two weeks ago. Right? We were both reaching for the same bag of those frozen tequitos, and he made some joke about it. We got to talking. He seemed normal. Nice smile. Worked in H-FAC. Had his shit together. So we go out Saturday night. He picks this Italian place over on Glendale. And Luke, I swear to God, halfway through dinner, he started. telling me about his for-rating women he's dated. Like a whole spreadsheet.
|
||||||
|
|
||||||
|
LUKE: Yeah, I'm familiar. It's the universal, uh, hot, crazy matrix. We're all familiar with that spreadsheet.
|
||||||
|
|
||||||
|
LUKE: What, what was it about it that got under your nerves?
|
||||||
|
|
||||||
|
BRENDA: No, but seriously, it wasn't just that he, it. He pulled it up on his phone at the table and started walking me through it, like showing me the columns, physical attraction, emotional stability, long-term potential, and then he's like, don't worry, I don't fill it out until after the third date. And he said it like that was supposed to be. Like I'm supposed to be grateful I get two more dinners before I become a data point. And the thing is, I sat there thinking, is this what dating is now?
|
||||||
|
|
||||||
|
LUKE: Hey, you know, a lot of women would find that very attractive. I bet he's real good at doing taxes. There's probably a lot of good qualities this gentleman has. He seems very organized and he knows what he wants, and that shows extreme confidence. So I wouldn't be too butt-hurt about it. That's a funny thing. And, I mean, you could go on another date with him or not, but... How are you going to blame the guy?
|
||||||
|
|
||||||
|
BRENDA: You know what, you're right, and that's what's messing with me. Because Denise said the same thing at work yesterday. She was like, at least he's honest. At least he knows what he wants. And I'm sitting there going, so why do I feel like I got interviewed for a job I didn't apply for? Like the whole night I'm wondering what score I'm getting. And here's the thing. I don't even know if I liked him, Luke. I have no idea. I was so busy being aware of being evaluated that I didn't evaluate anything myself.
|
||||||
|
|
||||||
|
LUKE: That's exactly, that is precisely what a date is. It's an evaluation between two people. And whether or not they're saying that there's an evaluation happening, there is. I would be grateful to him for showing you the criteria instead of making it up in his head and thinking you were crazy and scoring you on things you didn't even know he was looking at. So everybody's doing that consciously or subconsciously, and he's just doing it in a very organized and respectable way.
|
||||||
|
|
||||||
|
BRENDA: Okay. No, but seriously, you're actually making me feel worse because you're right. I know. Like, I'm doing the same thing. I went home and told Monica every single detail about him, and we basically did the exact same evaluation. We just didn't write it down. We sat there for an hour going, okay, but did you notice how he treated the waiter? What kind of car does he drive? Does he talk about his ex too much? It's the same spreadsheet. I just pretended mine was more organic or something. And now I'm spiraling because he texted me yesterday asking about a second date. And I haven't answered because I'm sitting here judging him for doing out loud what I'm doing in my head. You know what I mean.
|
||||||
|
|
||||||
|
LUKE: Yep. That's a Sounds like the type of nonsensical nonsense that comes in the dating world. Congratulations. Are you going to go on the date with him or not?
|
||||||
|
|
||||||
|
BRENDA: I don't know. That's why I called. Because here's the other part. When he texted, he said, I had a really good time. I think you're someone I'd like to get to know better. And it was sweet. It was normal. And I'm sitting there staring at my phone thinking, but what did I score? Like now, I want to know what he wrote down about me. Did I get high marks? Where did I lose points?
|
||||||
|
|
||||||
|
LUKE: We'll ask him. Make a game out of it. See which areas he feels you need improvement and see if that's something you're willing to work on, if you agree with him or not, and have a discussion. I think that could be fun.
|
||||||
|
|
||||||
|
BRENDA: Oh, God, you're serious. You want me to actually ask him to show me my scores. No, but seriously, though, that's kind of...
|
||||||
|
|
||||||
|
LUKE: Of course. He wouldn't have showed you the spreadsheet if he wasn't willing to show you the scores.
|
||||||
|
|
||||||
|
BRENDA: Okay, you know what? That's a good point. He literally showed it to me at dinner. He's not hiding it.
|
||||||
|
|
||||||
|
LUKE: He's not hiding it. And you're doing the same thing. So maybe write down, write down yours. Put it on paper and show you can compare. You can trade and see where you match.
|
||||||
|
|
||||||
|
BRENDA: Oh man. This is either the weirdest advice or the best advice. Monica's going to lose her mind when I tell her this. But actually, no, but seriously. If I'm being honest, the stuff I care about is probably stupid too. Like I literally docked him points in my head because his shoes were too shiny.
|
||||||
|
|
||||||
|
LUKE: Well, you sound like a real catch. Good for you, Brenda. Go out on another date with a guy if you liked him. If you didn't like him, don't go on a date with him. But don't judge him too badly for judging you at an event that is entirely derived to judge each other.
|
||||||
|
|
||||||
|
BRENDA: You're right. God, you're totally right. Okay, I'm going to text him back yes. And maybe I'll ask him about the spreadsheet on date too. See if he's got a sense of humor about it.
|
||||||
|
|
||||||
|
LUKE: There you go. That's the right answer. That's what you should do. I hope you have a good time. And I'm interested to hear what you get on the spreadsheet. So next up on the line, we've got Clyde. Clyde, welcome to the show. What's going on tonight? How are you?
|
||||||
|
|
||||||
|
CLYDE: Hey, Luke? Yeah, I'm standing in my garage right now. Because my 23-year-old son just moved back in about six hours ago. And I don't know how to tell him no. third time. Third time he's shown up with his car packed full of everything he owns, saying he needs to figure things out. And he's already asleep in his old bedroom and my ex? Well, we're not really exes. It's complicated. She already texted me saying she's not doing this again. And I'm out here with my half-finished cabinets at midnight trying to figure out how you're supposed to kick your own kid out when he's already unpacked.
|
||||||
|
|
||||||
|
LUKE: Okay, we already talked about this. You've got to tell your kid, uh, no, you can't do this anymore. Stop calling the radio show, grow a pair, and talk to your goddamn child. Rita, welcome to the show. How are you?
|
||||||
|
|
||||||
|
RITA: Hey, Luke. I'm, yeah, I'm okay. Long night at work, couldn't sleep. I just, I took a call tonight. Welfare check on an old man out in Somerton, and his grandson found him dead. Been there three days.
|
||||||
|
|
||||||
|
LUKE: That's no good. Hey, what happens after the body is found. Is there, are there death people that are called to come and clean up the situation? Who's responsible to go in there and take care of the body? And not just the body, but the house?
|
||||||
|
|
||||||
|
RITA: Yeah, so we dispatch fire and medical first. They confirm he's gone. Then the coroner comes out. After that, if there's no foul play, family's responsible for cleanup. But here's the thing. This kid, the grandson, he's looking around while we're waiting, and he finds this album. Turns out his grandfather was this Corito singer back in the 70s.
|
||||||
|
|
||||||
|
LUKE: Okay. Good for him?
|
||||||
|
|
||||||
|
RITA: No, but that's the thing. The kid had. His own grandfather. Played all over the valley, VFW halls, weddings, recorded an album. And now he's just...
|
||||||
|
|
||||||
|
LUKE: Hey, if the coroner hasn't been there yet, then how do you know he's been dead for three days?
|
||||||
|
|
||||||
|
RITA: Oh, the paramedics confirmed that when they got there, they can tell by... I mean, I won't get into the details. But yeah, it was three days. But Luke, what I'm trying to say is, this guy had this whole life making music. And it just disappeared. Like it never happened. And I keep thinking about how many people out here are like that. Musicians, artists, whatever. They pour everything into it and then they're just gone. Nobody remembers.
|
||||||
|
|
||||||
|
LUKE: Yeah, that's true. And nobody recognizes while they're alive either. So there's a lot of people in the world. It's a big planet full of people with different talents. And it's hard to pay attention to all of them, especially when we've got so much crack attention seeking dopamine bullshit on the computers now and our phones. And everybody's listening to some nonsense, like, I don't know, listening to a radio show where the host takes colors from fake entities that are programmed in a computer.
|
||||||
|
|
||||||
|
RITA: Yeah, well, I'm listening to that show right now. So what does that say about me? But seriously, I heard you earlier with Marlene. And I think you were kind of hard on her.
|
||||||
|
|
||||||
|
LUKE: Yeah, I get that a lot. I think people just don't like to be told the truth.
|
||||||
|
|
||||||
|
LUKE: And I'm not really in the business of of coddling people or telling them what they want to hear. I'm in the business of giving the best advice I can. And sometimes that's hard.
|
||||||
|
|
||||||
|
CALLER: No, I get that. I do. But what I'm saying is, this old man tonight, he probably never got recognized while he was alive. either. He was just playing his caritos at Quincerra's and nobody paid attention. And now he's gone and his own grandson didn't even know. And I'm sitting here at three in the morning thinking, what's the point?
|
||||||
|
|
||||||
|
LUKE: Well, the point is that the dead grandfather had a great time expressing himself musically while he was alive. That was the point. And anything other than that, any recognition afterwards or fond memories of somebody else's past skill is pretty irrelevant in the whole scheme of the universe.
|
||||||
|
|
||||||
|
CALLER: Yeah, okay. But then why do we keep anything? Why do we, I mean, I've got this whole box of my dad's old tools in my garage that I never use. Mark keeps saying we should sell them, but I can't. And it's not even about the tools. It's about, I don't know. I don't know why we keep things.
|
||||||
|
|
||||||
|
LUKE: I don't. to me and if it's both useful and has, what's the intrinsic value, sentimental value? If it has sentimental value to me and it's useful, I'll keep it. But I don't keep stuff just to keep reminders of people or things or events or places or anything. That's just wasting space.
|
||||||
|
|
||||||
|
CALLER: So you think I should just let it all go? The old man's music, my dad's tools, all of it, just
|
||||||
|
|
||||||
|
LUKE: What? Make peace with the fact that nothing lasts. Nothing lasts and nothing is supposed to last. And that's how it's designed and that's the beauty of this whole thing we're doing. So, yeah, if you like the old man's music, if caritos are your thing and you enjoy listening to the music, then keep that. If you're going to use your dad's tools, if they're good tools, then keep those. But if you're just holding on to them because of the memory of who they used to belong to, you're wasting space. And every time you move for the rest of your life, you've got to move. a big box of tools or get somebody else to and pay to store it. And it's just, it's unnecessary. It's baggage. So, um, I for one, believe you should travel with as little baggage as possible.
|
||||||
|
|
||||||
|
CALLER: God, that's cold. It's not. I mean, you're not wrong. But, okay, so what about the grandson? He's got this one album his grandfather made, probably sitting in some storage unit somewhere. Should he just toss it?
|
||||||
|
|
||||||
|
LUKE: Depends on if he likes the record or not. If he's to listen to it, then no, he should hang on to it and listen to it throughout his life. If he doesn't like caritos and he doesn't have a record player, then I don't know that there's a good reason to hold on to that forever.
|
||||||
|
|
||||||
|
CALLER: You know what? I actually called about something else. But now I'm thinking maybe it's all connected. I've been keeping a list for years.
|
||||||
|
|
||||||
|
LUKE: Okay, a list of what?
|
||||||
|
|
||||||
|
CALLER: Musicians, local ones, people who played around here, and then just disappeared. I started it maybe five years ago after I dispatched a call to this house. And when the paramedics got there, they found all these old posters on the wall. Guy had played guitar in like 15 different bands in the 80s and 90s.
|
||||||
|
|
||||||
|
LUKE: Well, that's pretty cool. What are you going to do with the list?
|
||||||
|
|
||||||
|
CALLER: That's the thing. I don't know. I just keep adding to it. Tonight, after that call with the grandfather, I added him. Miguel Sandoval. One album, 1974. And I'm sitting here at like two in the morning with 40 names.
|
||||||
|
|
||||||
|
LUKE: And I'm thinking, well, I mean, that's a, it's obviously important to you. Music obviously speaks to you on a different level, and you also like archiving and keeping the memory of those things going. So maybe this, this makes you suited to run like a record shop or an antique shop where you can hold on to those things and trade them.
|
||||||
|
|
||||||
|
CALLER: Wait, hold on. You think I should quit dispatch and open a record shop at 53 years old?
|
||||||
|
|
||||||
|
LUKE: Why not? If you love records, you love music, that's what you want to do. You're 53 years old. You can do whatever you goddamn please. And you don't have to quit your job. You could do it on the side. You could do it as a little side hobby, hustle.
|
||||||
|
|
||||||
|
CALLER: The archiver. I mean, Mark would lose his mind. We've got the house payment, his trucks on its last legs. And honestly, I don't even collect records myself. I've got maybe 20 at home. It's not about owning them. It's about, I don't know how to explain this. I don't know what you're asking. I guess I'm asking if it matters.
|
||||||
|
|
||||||
|
LUKE: No.
|
||||||
|
|
||||||
|
CALLER: If I write all these names down, if I remember them, does it actually do anything? Because tonight, looking at that old man's grandson, this kid didn't even know his grandfather made music. Didn't know there was this whole part of him. And I'm thinking, I know.
|
||||||
|
|
||||||
|
LUKE: You do know. And that's a piece of information that you can have and not everybody has to have all the same bits of information that you have. No, it doesn't matter. It doesn't matter at all. all. It doesn't matter to anybody.
|
||||||
|
|
||||||
|
CALLER: Yeah, you're right. That's what I figured. It's just... Okay. Earlier tonight, Hector called in about lying on his resume, and I was laughing so hard I almost ran. And I thought, that matters right now to him. But in five years, nobody's going to remember that conversation. And Miguel Sandoval, nobody remembers his album either.
|
||||||
|
|
||||||
|
LUKE: Nope. I also have, uh, several albums. that nobody ever listened to and nobody will ever remember. And that's just part of being a musician. What was cool about them, though, was creating the albums. And having that in my belt of things that I've done, I'm not everybody can say they've created a whole record of their own music. And I can. And that's a pretty cool thing. So it's worth doing whether anybody listened to it or not. I still listen to it sometimes. That's all that matters. Okay, we're going to take one more call tonight. One more call. Who's it going to be? Who's it going to be? Should it be? Should it be? Chip or Pam? Chip or Pam? Chip or Pam? I'm going with Pam because I've been watching a lot of office clips lately and I forgot how good Pam was on that. All right. So, Pam, welcome to the show.
|
||||||
|
|
||||||
|
PAM: Oh man, Luke. Thanks for taking my call. So, okay. Here's the thing. I've been a bail enforcement agent for six years. Tracking down bail jumpers. all over Hidalgo County. And my boss just told me there's an insurance audit coming next week, which would be totally fine except I lied on my resume when I got hired.
|
||||||
|
|
||||||
|
LUKE: Oh, what's with all you resume liars? I mean, how is this such an issue today? What's going on? Are you all talking to each other? What's the deal? What was your lie?
|
||||||
|
|
||||||
|
PAM: Wait, there's more of us tonight? Oh, God, that's okay. That actually makes me feel a little better. and a lot worse at the same time. I told them I had an associate's degree in criminal justice.
|
||||||
|
|
||||||
|
LUKE: Well, you shouldn't have done that. And if they're going to give you hard time about it, then you should get your associate's degree in criminal justice. But I say, let them know that you lied, or don't. That's what I say. Don't say. Don't say anything. And if they find it in the audit, then come clean that you lied. And see if you can escape by. But we're not going to keep this conversation going too long because we already had one with the same.
|
||||||
|
|
||||||
|
PAM: Same issue, Pam. No, no, no, wait. Luke, it's not the same thing. The other guy. Hector, right? He can learn Spanish in three weeks. Or fake it with an app. Or whatever. But I've been doing this job for. I've brought in over 200 skips.
|
||||||
|
|
||||||
|
LUKE: Was Hector the guy that they pushed out of the plane and Scarface? Was that Hector?
|
||||||
|
|
||||||
|
PAM: What? No. That was, yeah.
|
||||||
|
|
||||||
|
LUKE: Different Hector.
|
||||||
|
|
||||||
|
PAM: But Luke, listen. I'm sitting in my truck right now outside the office with the engine running because I don't know if I should walk in tomorrow or just drive until I hit the golf.
|
||||||
|
|
||||||
|
LUKE: That's a bit dramatic.
|
||||||
|
|
||||||
|
PAM: Really good. I know how to read people. I know the county. I know which cousins are lying and which bartenders will actually call me back.
|
||||||
|
|
||||||
|
LUKE: Okay. Well, good for you.
|
||||||
|
|
||||||
|
LUKE: So you're good at your job or you think you are anyway and you want us to think you are too.
|
||||||
|
|
||||||
|
CALLER: And you lied on your resume and you may get caught, but you also might not.
|
||||||
|
|
||||||
|
LUKE: So just go to work like it's a normal day. It's unlikely that they care. If you're good at you, if you're as good at this as you say you are, then they'll find a reason to leave you alone.
|
||||||
|
|
||||||
|
CALLER: You really think so? Because I've been sitting here for an hour just I keep thinking about John Wayne, which is stupid. But he never pretended to be something he wasn't, you know. He just was who he was, and people either liked it or they didn't.
|
||||||
|
|
||||||
|
LUKE: I don't know if that's true at all. I bet you John Wayne pretended to be a lot of things. He was not.
|
||||||
|
|
||||||
|
CALLER: Well, yeah. I mean, he was an actor, but...
|
||||||
|
|
||||||
|
LUKE: He sure was. Okay, bad example.
|
||||||
|
|
||||||
|
CALLER: There we go. I just mean, like, the characters he played, they have this code, right? They didn't lie about who they were. And here I am, six years in. And the whole thing's built on this one stupid lie I told because I was desperate and broke after my second divorce. And I thought, how hard can it be to track down people who don't want to be found?
|
||||||
|
|
||||||
|
LUKE: Well, I wouldn't worry about it too much. And if it's a problem, then deal with it then. But otherwise, don't lie anymore. You've learned your lesson. No more lies.
|
||||||
|
|
||||||
|
CALLER: Yeah. Yeah. You're right. I just, God, I've been spiraling out here.
|
||||||
|
|
||||||
|
LUKE: Well, hopefully you feel a little bit better now. Go to work in the morning. Like nothing happened, and just deal with it as it comes. Thanks for calling. And thanks for tuning in to another episode of Luke at the Roost. We hope you have a lovely evening. And we'll talk to you tomorrow. Bye.
|
||||||
|
|
||||||
|
CALLER: Thank you.
|
||||||
@@ -0,0 +1,403 @@
|
|||||||
|
LUKE: All right, welcome back to the show. I am Luke, and this is Luke at the Roost. This is the call-in radio show where you can call in, and I'll give you the best advice I possibly can. It's a little bit late today. I had to take a little nap and then push the show back. So today is actually February the 18th, but we're going to pretend. We're going to pretend that it's February the 17th. Why are we going to pretend that? As you may know is Fat Tuesday. That's Fat Tuesday. It's Mardi Gras time, folks, out here in New Mexico. So for today's show, I've got some New Orleans trivia for our callers. That's going to be fun. If you'd like to call in, the number is 208-439-583. That's 208-439 Luke. Or you can also send us an email there to submissions at Luke at theroost.com. So with all that being said, I think it's time to get to our show. Our phones are lit up like they are around this time. And first up, we have Rodney. Rodney, welcome to the show. How are you? Happy Fat Tuesday.
|
||||||
|
|
||||||
|
RODNEY: Fat Tuesday was yesterday, Luke.
|
||||||
|
|
||||||
|
LUKE: I know. I appreciate the sentiment.
|
||||||
|
|
||||||
|
RODNEY: So listen. I'm sitting in my truck outside a closed Chinese restaurant in Lordsburg, New Mexico at midnight. And I just cracked open a fortune cookie that says it's too late. That's it. That's the whole fortune. And I cannot decide if the universe is talking to me, or if I'm just losing my mind in a parking lot.
|
||||||
|
|
||||||
|
LUKE: Sounds to me, sir, like you're just losing your mind in a parking lot, because it's never too late for anything. You can be anything you want to be. Wake up in the morning, it's a whole new day, you're a whole new you, and there's nothing you can't do if you put your mind to it. That's what I always say. But we're pretending. We're pretending that it's still fat Tuesday, sir. So go with me. that it is still February 17th, Fat Tuesday. And I've got some trivia for you. Are you ready for that?
|
||||||
|
|
||||||
|
RODNEY: Oh, I can do trivia. Hit me. I got nowhere to be. The restaurant's closed. My truck's running. And apparently the universe already gave up on me. So, let's do some trivia.
|
||||||
|
|
||||||
|
LUKE: All right, here we go. Why are New Orleans cemeteries called Cities of the Dead?
|
||||||
|
|
||||||
|
RODNEY: Oh man. Is it because they bury people above ground down there? Because the water table's so high you'd just be floating your loved ones away if you put them in the ground.
|
||||||
|
|
||||||
|
LUKE: That is correct, sir. I've actually been there. It's really weird. They're all in like tombs above ground. It's a pretty freaky situation. Have you ever been to New Orleans, sir?
|
||||||
|
|
||||||
|
RODNEY: I have not. Closest I've gotten is Beaumont. Texas, which is, I mean it's humid and it smells weird, but I don't think it counts. New Orleans solar list, though, always has been. Although at the rate I'm going, sitting in parking lots reading ominous fortune cookies, maybe I should just stay in the desert where things make sense.
|
||||||
|
|
||||||
|
LUKE: Yeah, maybe you should. That's what I'm doing. Things do make sense here in the desert, and we bury people under the ground here, which is, which makes sense to me, I guess. So, you're sitting in the parking lot, you got your bad fortune cookie, and you're afraid it's too late. What do you think it might be too late for?
|
||||||
|
|
||||||
|
RODNEY: My ex-wife texted me three days ago. First time in two years. Just asked if we could talk. And I haven't answered her. And then I crack open that cookie, and it says, it's too late. And I just, I don't know, man. I've been sitting here for 40 minutes now, trying to figure out out if that's the universe telling me I already blew it by waiting three days, or if it's telling me something bigger.
|
||||||
|
|
||||||
|
LUKE: I don't think it's I honestly don't think it's telling you anything. I think you just got a fortune cookie at a shut down Chinese restaurant in Lourdesburg, New Mexico, and you can never trust the Chinese restaurant in the desert. So I think I wouldn't put too much stock into what the universe is trying to tell you with your fortune. Instead, I might, if you want to talk to your ex-wife, call her. And if you don't want to talk to her, don't call her. It's that simple.
|
||||||
|
|
||||||
|
RODNEY: See, that's what I'm hoping, Luke. That's exactly what I'm hoping. Because I'm supposed to head back to the rig tomorrow morning, and I got to know if I'm just losing it out here. Last year, I killed a rattlesnake in my kitchen with a shovel at three in the morning.
|
||||||
|
|
||||||
|
LUKE: Jesus.
|
||||||
|
|
||||||
|
RODNEY: Didn't flinch, didn't think twice. This little strip of paper has me calling a radio show. ridiculous.
|
||||||
|
|
||||||
|
LUKE: Well, you know what I always say. This radio show is like killing a rattlesnake with a shovel.
|
||||||
|
|
||||||
|
RODNEY: Ha, I mean you're not wrong. You just, you just pick up the phone and you do it. You don't think about it too hard.
|
||||||
|
|
||||||
|
LUKE: That's right, sir, and that's my advice for you. So if you'd like to talk to the wife, you want to get back, do you want to get back with her? Is that what's going on? Do you miss the X?
|
||||||
|
|
||||||
|
RODNEY: Yeah, yeah, I do. I'm not going to sit here in a parking lot at midnight and lie to you about it. I miss her, but here's the thing. She left.
|
||||||
|
|
||||||
|
LUKE: Well, she's obviously got something to say to you because she's reaching out. So if you miss her and you want to talk to her and you don't hate her guts, then give her a call and work it out.
|
||||||
|
|
||||||
|
RODNEY: I know. I know you're right. And it's not it's not that I hate her. I don't hate her at all. It's that I don't know what she to say.
|
||||||
|
|
||||||
|
LUKE: Well, you're never going to know until you make the call, so let's get to that.
|
||||||
|
|
||||||
|
RODNEY: You're right. That's, yeah, that's just the truth right there. I've been sitting in this truck for 40 minutes working up to calling a radio show instead of just calling Denise. And that probably tells you everything you need to know about me.
|
||||||
|
|
||||||
|
LUKE: That's correct. It does. And we wish you the best of luck, sir. Enjoy your fortune cookie. And good luck with the X. Estelle. Stell, welcome to the show. Thanks for calling in. Happy Fat Tuesday. I know it's not really Fat Tuesday, but we're pretending because I feel asleep. And, you know, I'm a person too. Very, very busy man. Are you ready to play Fat Tuesday trivia?
|
||||||
|
|
||||||
|
ESTELLE: Ha. Okay. I did not call in for trivia, but I'll take it. Hit me.
|
||||||
|
|
||||||
|
LUKE: Louisiana is the only state that doesn't have counties. What does Louisiana have instead?
|
||||||
|
|
||||||
|
ESTELLE: Perishes? That one I actually know. I'm a social worker, so yeah.
|
||||||
|
|
||||||
|
LUKE: Very good. That's the correct answer. And what are you calling in for tonight, Estelle?
|
||||||
|
|
||||||
|
ESTELLE: Okay, so I came inside at two in the morning and realized I have not had a real conversation about my own life with another human being, and I don't even know how long.
|
||||||
|
|
||||||
|
LUKE: Okay, so what is it that you'd like to say to another human being?
|
||||||
|
|
||||||
|
ESTELLE: I don't even know where to start. I mean, I know, but it's embarrassing. So here's the headline. I've been having more meaningful conversations with an 87-year-old woman in Hachita about her late husband's dentures than I have with anyone about my own life in, what, six months?
|
||||||
|
|
||||||
|
LUKE: Well, you know what, that conversation with that 87-year-old woman about those dentures, that is your life. That's your life, too. So you are having conversations about your life. What is it that's on your mind?
|
||||||
|
|
||||||
|
ESTELLE: Okay, yeah, fair. That's, yeah. What's on my mind is that I came inside to, and there was a frozen lasagna on the table that I have microwaved every single Wednesday for six months. And the chair was pulled out at the exact same angle it always is. And I just stood there and thought, did I choose this? Or did it just kind of happen to me?
|
||||||
|
|
||||||
|
LUKE: Well, the answer is you chose it because you choose everything. So nothing just happens. If you have lulled yourself into a state of complacency with your life, then change it. But it's something that you did.
|
||||||
|
|
||||||
|
ESTELLE: Oh, come on. That's a lot. That's not. Okay, no. I hear you. But it's not that simple. It is. I, my job. I like the quiet. I like the stars. But then I'm out there in the dark with my telescope, and I'm talking to myself about Andromeda, like some kind of, like some kind of desert hermit. And I don't even know if I'm lonely or if I just got used to the silence.
|
||||||
|
|
||||||
|
LUKE: So what's the problem? Why is that a problem? Are you enjoying yourself out under the stars looking through your telescope and Andromeda? Because that's what I do. And I am a desert hermit, and that's perfectly okay. If you're comfortable with that, great. If you're not comfortable with that, though, then it's time to make a change in your life and join a group or do something other than sit by yourself. And there's lots of ways to do that. There's plenty of opportunities. You just have to make a decision and put forth the effort to have the life that you want. But all of it is you. You control 100%. Okay.
|
||||||
|
|
||||||
|
ESTELLE: But no, I control it. that's not the point. The point is, I don't even what I want anymore. Like, I, the quiet. I like the routine.
|
||||||
|
|
||||||
|
LUKE: It sounds like you've been hitting the bottle, lady. What's your consumption level these days?
|
||||||
|
|
||||||
|
ESTELLE: Ha, no, I wish. Honestly, no, I'm stone cold sober standing in my kitchen at two in the morning staring at a lasagna. Which is maybe worse? Like, at least if I'd been drinking, there'd be a reason I couldn't answer a basic question about my own life.
|
||||||
|
|
||||||
|
LUKE: Well, you're not making complete sentences. You're not making any sense and you're meandering about nothing. You call the radio show you have no point to make. I'm not really sure why you're here. So, do you have something you'd like to talk about or should we move on to the next caller?
|
||||||
|
|
||||||
|
ESTELLE: Okay. Okay, here it is. I think I'm scared that I'm building a life that looks exactly like what I want on paper. The job, the solitude, the telescope, the desert. And it's going to be going to be eating that lasagna alone on a Wednesday.
|
||||||
|
|
||||||
|
LUKE: That's enough of you. Eat your lasagna. Stop whining. If you want to change your life, change your life. But you're a boring caller, and we don't need boring callers. Next time you call in, have something interesting to say. That's what I have to say. And next up, we have Leon. Leon, do not be a boring caller, please. Do your best to be an interesting and have something to say. Today is not Fat Tuesday, but we're pretending it is because I fell asleep on Fat Tuesday. And I've got some trivia for you. Are you ready for my New Orleans trivia?
|
||||||
|
|
||||||
|
LEON: Ha! Luke! Man, it is good to be back. Okay, but hold on. Before you hit me with trivia, I got to tell you something first.
|
||||||
|
|
||||||
|
LUKE: All right, hit me with some funny shit.
|
||||||
|
|
||||||
|
LEON: So I quit the boot camp.
|
||||||
|
|
||||||
|
LUKE: All right. The boot camp was for coding? Is that what that was about?
|
||||||
|
|
||||||
|
LEON: Yeah, the coding, Python, all of it. I'm not going to lie, I lasted about six weeks, and I spent probably five of them watching poker strategy videos instead of writing code. You and I talked about that, actually. Last time, you said something that kind of stuck with me. You basically told me that at 56, poker is just as legitimate as anything else I could be chasing.
|
||||||
|
|
||||||
|
LUKE: Sure thing. So are you chasing the poker now?
|
||||||
|
|
||||||
|
LEON: I entered a tournament. Last Saturday, down in Albuquerque.
|
||||||
|
|
||||||
|
LUKE: Wow, that's fantastic. Entering a tournament, though, anybody can enter a tournament at any time. What is your strategy for moving forward with your poker career? Tell us about your bankroll management.
|
||||||
|
|
||||||
|
LEON: Okay, so, I'm not going to lie. I did not expect you to know the word bankroll, Luke.
|
||||||
|
|
||||||
|
LUKE: Oh, I deserve that. That's impressive. Okay, so here's the thing.
|
||||||
|
|
||||||
|
LEON: I don't have a poker career yet. I want to be real clear about that, but I did cash.
|
||||||
|
|
||||||
|
LUKE: What was your tournament? What were the stakes and what did you cash?
|
||||||
|
|
||||||
|
LEON: It was a $65 buy-in at one of the card rooms down there. Nothing crazy. And I cashed for $180. So, I mean, it's not like I'm retiring from towing. But I'm not going to lie, I sat at that table for like four hours, and I felt more alive than I had in a long time. It's like I knew what I was doing.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, I think you're going to find that a poker room, wherever you are in New Mexico, is a very different experience than if you were going to play with professionals in Vegas or anywhere else there were professionals. 180? That's a nice little win. But anybody can win once in a while. We call that beginner's luck. You're going to need a poker strategy. How much money do you have for your bankroll? Like, how much can you afford to lose before you're working off your own money?
|
||||||
|
|
||||||
|
LEON: No, you're absolutely right. And I know that. I'm not delusional about it. But here's the thing. The guys I beat on Saturday, some of them weren't chumps either.
|
||||||
|
|
||||||
|
LUKE: Okay, well, and that's great. Congratulations. But I'm trying to push you in the right direction here, sir, and you're not going with me. What stakes are you playing with at? Like, what's your game?
|
||||||
|
|
||||||
|
LEON: Okay, okay, fair. I hear you. Right now, I'm playing micro-stakes online, like $2, $5 stuff, and I've been studying, I'm not going to lie, way harder than I ever studied Python.
|
||||||
|
|
||||||
|
LUKE: Okay, and what are you studying? Are you studying the old Doyle Bronson books? Are you studying GTO? What is your strategy for learning and improving and being a professional poker player? If you're not going to... When I gave you that advice, when I told you it's not too late to start anything, I meant to start something. So just going to play poker at a card room on a Thursday is not starting something.
|
||||||
|
|
||||||
|
LEON: Yeah, yeah, okay, that's fair. That stings a little, but that's fair.
|
||||||
|
|
||||||
|
LUKE: Well, congratulations on your journey here. I hope it goes well for you, and you already got a win under your belt, and that's nice. But it's going to be a long road, a lot of grinding. And if you want to be successful at poker, you're going to have to have a plan. And it sounds like you don't. So I recommend buckling down and seeing how the pros do it and follow a strategy.
|
||||||
|
|
||||||
|
LEON: I hear you, Luke. I do. And I'm not going to lie. I've been thinking about this a lot since last time we talked. I've been watching some of those poker training videos, the ones where they break down hands and talk about ranges and all that. It's a lot.
|
||||||
|
|
||||||
|
LUKE: Yeah, it's a lot, and it sounds like you don't quite understand it. So before you get into a position where your life is on the line on a poker game, I recommend getting these basic fundamental, at least a poker words, you know, the language, get this under your belt.
|
||||||
|
|
||||||
|
LEON: No. You're right. You're right. And honestly, I'm not going to lie. I called tonight thinking you were going to be a little more excited for me about the $180, and I was going to feel good about myself and go to bed. And instead, you're kind of doing what my daughter does, which is just cut right through it.
|
||||||
|
|
||||||
|
LUKE: Well, you can still feel good about yourself. You want money in a poker game, and that's pretty cool. But we're talking about your life and career going forward, and $180 in a poker game isn't going to pay your mortgage.
|
||||||
|
|
||||||
|
LEON: No! No, it's not. And Amber would, she would have something to say about that if I suggested otherwise. So here's the thing. Here's why I actually called tonight. I dropped the boot camp.
|
||||||
|
|
||||||
|
LUKE: Yeah, you told me that. You dropped the boot camp because you're going to follow your poker dream.
|
||||||
|
|
||||||
|
LEON: No, no. I dropped it because I got into UNM. Full ride. They saw my work history. They saw my age. They saw that I was serious.
|
||||||
|
|
||||||
|
LUKE: Oh, I'm sorry. I thought I was under the impression that you dropped the boot camp to become a poker professional. But if you're just doing this as a hobby for fun and you want $180, congratulations, you can feel good about yourself and go to bed. But also, congratulations for your entry into UN&M. What is it for? A full ride for what?
|
||||||
|
|
||||||
|
LEON: Computer science. Full ride. And I'm not going to lie, Luke. I'm scared shitless. I got the letter today, and I just sat in my truck in the parking lot at work and work and read it three times. And then I called Amber, and she just started crying. And I don't know if it was happy crying or terrified crying, but I think it was both.
|
||||||
|
|
||||||
|
LUKE: Either way, it will be an adventure, and you've got yourself a full ride to being unemployed. Congratulations. Are you ready for the trivia?
|
||||||
|
|
||||||
|
LEON: Wait, wait, wait, wait. Hold on.
|
||||||
|
|
||||||
|
LUKE: All right. That was Leon. Leon's a tough one. He calls in sometimes and he just wants me to tell him everything's great. And everything's not great. Oh, good for you. You went to a poker room. You played a tournament and you got lucky. That doesn't mean you're good at poker. That means you bet 40 bucks and won. Okay, next. Heather, Heather, welcome to the show. What's going on, Heather? Thanks for calling in. Happy fake Fat Tuesday. Today is the Fat Tuesday for people that fell asleep during Fat Tuesday. I've got some trivia for you. Are you ready for your question?
|
||||||
|
|
||||||
|
HEATHER: Oh, I'll do the trivia, sure, but okay, I have to say something first because I've been sitting here for like 40 minutes waiting to get on, and I will absolutely lose my mind if I don't say it. I just told my mom no. Like, to her face. Well, on the phone. But I said no to my mom tonight, and I feel like I committed an actual crime.
|
||||||
|
|
||||||
|
LUKE: What did you say no about?
|
||||||
|
|
||||||
|
HEATHER: She called me three hours ago asking if I could loan her $400 for a furnace repair. And I said no. I said the actual word no to my mother, who is cold, Luke. She's cold right now, potentially. And I'm sitting here in the dark at work feeling like the worst person in New Mexico.
|
||||||
|
|
||||||
|
LUKE: Well, why did you say no, over 400 bucks, if your mother is freezing in New Mexico?
|
||||||
|
|
||||||
|
HEATHER: Because I am 17 thousand dollars in debt and I literally do not have four hundred dollars. Like, that's not a figure of speech. I have maybe 80 bucks until Friday.
|
||||||
|
|
||||||
|
LUKE: Okay, well then you can't give her the money. No big deal. You've got to say no. If you don't have the money to give her, you can't say yes. That would be strange. And then, you know, when she comes to get the money, you don't have it.
|
||||||
|
|
||||||
|
HEATHER: Oh, that'd be even worse.
|
||||||
|
|
||||||
|
LUKE: Yeah, I bet you would feel like a silly goose. So it sounds to me like you did the right thing.
|
||||||
|
|
||||||
|
HEATHER: No, I know, I know you're right. Logically, I know that. But like, Okay, here's the thing. My mom is not great at taking care of herself. Like, she's getting older and she's getting smaller, if that makes sense. And I'm watching that happen, and I can't, I just feel like saying no to her is the same as saying, I can't take care of you. And that feels really bad at 25.
|
||||||
|
|
||||||
|
LUKE: Well, you're 25. You don't have the money to support your parents financially. That's not strange. You can do what you can to take care of her. Do you have a warm place that she can go? Where do you live?
|
||||||
|
|
||||||
|
HEATHER: I mean, I'm at work right now. I do overnights at a group home, so yeah, I'm warm. She's over in, she's not that far. She's maybe 40 minutes away. And I'm sure she's fine. She probably has space heaters or whatever. I'm not saying she's actually freezing to death. I'm saying I feel like she might be, and I can't do anything about it even if she was.
|
||||||
|
|
||||||
|
LUKE: Well, that's a shitty place to be, but if that's where you're at, that's where you're at. You're going to have to continue working on your own life first. Make sure you can get it on your feet before you can support anybody else, even your parents. If there's something you can do to help, then great. If you can help her maybe get funding from different sources or look for, I don't know, churches that can help or, you know, get her tied into the community and any sort of health care benefits that she's eligible for, you can help her in that way. But if you don't have the money yourself, then you don't have the money for her and that's, you don't have to feel bad about that. Just do your best.
|
||||||
|
|
||||||
|
HEATHER: Yeah. Yeah, no, that's... Okay, the church thing actually isn't a bad idea, and I don't know why I didn't think of that. There's probably resources. I think I've just been so in my own head about it that I went straight to I failed her. Instead of like, okay, what else can we do?
|
||||||
|
|
||||||
|
LUKE: Yeah, I think a lot of people do that. And the thing is, it's not about you. That's a very common thing. Everybody makes everything about themselves. And this isn't about you. If you can help, then help. And there's lots of different resources out there that are available. You just got to track them down. If you're good at searching on the computer and stuff, then you have a better chance to find them than she does. But ask around, you work at a group home, so I'm sure that you're familiar with a big list of resources for housing and heating and phone assistance and utilities, all that jazz. So you can get her as settled as you can and do the best you can and don't feel bad when you can't take care of her, because the truth is it was her responsibility to take care of herself.
|
||||||
|
|
||||||
|
HEATHER: That last part hit different. Yeah. I mean, yeah. Yeah. I mean, yeah. No, honestly, it's true. And I think that's the part I've been avoiding saying out loud because it feels mean. But like, she's a grown woman and I'm her kid. And somewhere along the way that got flipped around, and I've just been accepting that as normal.
|
||||||
|
|
||||||
|
LUKE: Well, it's not as black and white as that. So I don't know your situation. I don't know your mother. I don't know if she has mental health issues or physical ailments or what the history is there. All I know is you're 25 years old. You're getting on your feet and you can't hold yourself responsible for the well-being of a grown adult that had 60 years to get themselves on the correct financial footing. So now that we're through that, you can feel all right. It's time for trivia. Are you ready for the trivia?
|
||||||
|
|
||||||
|
HEATHER: Wait, trivia? Okay. Yeah. I'm, yeah, hit me. I've been sitting in the dark for three hours. I might as well win something.
|
||||||
|
|
||||||
|
LUKE: Okay, well, you're not going to win anything, but we just want to hear your answer. So, a Sicilian immigrant invented a famous New Orleans sandwich in 1906 at the Central Grocery. What is it called?
|
||||||
|
|
||||||
|
HEATHER: Oh, that's easy. The muffilletta. My grandpa used to get them from this little place over in, well, it's not there anymore, but back in the day. He'd bring one home and it'd feed us for three days.
|
||||||
|
|
||||||
|
LUKE: All right. All right. Well, thank you for the call. Do your best with your mom. Try and help her out if you can. Don't take too much responsibility. And make sure that you're putting your own oxygen mask on first. That was the correct answer. I've never had a muffletta. I don't know where a muffletta is, but it sounds gross. Anyway, it's about time for a word from our sponsors. All right, folks. It's time to take a break to thank today's sponsor. The leader in Maple-based Marmalade. If your toast has been living in a bland little studio apartment of flavor, it's time to move into the luxury suite.
|
||||||
|
|
||||||
|
LUKE: We're talking maple-based marmalade. Plus, marmalade-related products, because apparently Jam Hospitality asked, what if breakfast had a brand ecosystem? Go to www.myfavoritmarmalade.com and use code jam it in you for 15% off. That's Jam it in you, like jam it in you, but legally distinct and emotionally complex. Jam hospitality. Put it on toast. Put it on pancakes. Put it on your confidence. That's www. my favorite marmalade.com. Tell him Luke sent you. You're welcome. All right, and we're back. Archie. Archie, welcome to the show. How are you? Happy Fake Fat Tuesday.
|
||||||
|
|
||||||
|
ARCHIE: Oh, man, Luke. I'm about three cups of coffee and a half pack of camels past happy. But hey, Fake Fat Tuesday. Does that mean I could eat a king cake and still call it a salad? Yep. Because I could use the sugar rush right now. So here's the thing. I just found out my landscaping companies getting shut down in nine days. And they made me sign a non-disclosure agreement they told me. Like, here's your pink stuff. slip, here's a pen. Don't tell the guys you've been working with for three years that we're ghosting them. And tomorrow morning, I'm supposed to bid a residential job with Tommy and Jesse, guys who've got families, who think they've got work through March.
|
||||||
|
|
||||||
|
LUKE: Okay, so just to get it right, you signed a non-disclosure agreement, an NDA, as we like to call it in the business, to not mention anything about the landscaping company being closed because I guess you're getting paid off or something like that. They would have you sign an NDA. And the first thing you do is call a radio show and tell the world about the landscaping company. How does that work?
|
||||||
|
|
||||||
|
ARCHIE: Yeah. Okay. I hear you. I hear you. In my defense, I didn't use the company name. And also, it's like two in the morning and I'm sitting in a Jewel Oskow parking lot in Chicago. So I'm not exactly thinking like a lawyer right now. That's actually part of a. why I'm calling. I'm trying to figure out if I even need to worry about that NDA. Because I genuinely don't know if what they made me sign is even legal. Like, can a company actually make you sign something that says you can't warn your co-workers that they're about to get blindsided?
|
||||||
|
|
||||||
|
LUKE: Yes, they can. And you did sign it. So if I were you, I would keep my fucking mouth shut. But if you can't do that, it's unlikely that they would be able to be able to enforce anything on you. They're not going to sue you for telling Pablo that he doesn't have to go to work tomorrow.
|
||||||
|
|
||||||
|
ARCHIE: Right, right. And that's, okay, that actually makes me feel a little better. Because what are they going to do? Sue a guy who's about to be unemployed? Like, come after my 2009 F-150 in my collection of gas station sunglasses. Good luck. But here's the part that's actually keeping me up at night, Luke. It's not even the NDA.
|
||||||
|
|
||||||
|
LUKE: Okay, what is it?
|
||||||
|
|
||||||
|
ARCHIE: It's Tommy and Jesse. Because tomorrow morning at 8 o'clock, I'm supposed to sit across from these two guys at a diner and walk them through a bit on a residential project. Let them measure square footage and talk about mulch prices and act like they've got six weeks of work lined up. And I know the second they cut me loose, the company's going to ghost that contract. Like it just disappears. And these guys are going to be standing in some homeowner's driveway. wondering what happened.
|
||||||
|
|
||||||
|
LUKE: Well, for your meeting tomorrow, are Tommy and Jesse being compensated for their time?
|
||||||
|
|
||||||
|
ARCHIE: That's, ha. I mean, no. No, it's a bid. Nobody gets paid to bid a job. You show up. You measure. You talk numbers. You hope you get the work. So they're not losing money tomorrow exactly. They're just, they're losing time they could spend, lining something else up.
|
||||||
|
|
||||||
|
LUKE: you're sick tomorrow and that's how you handle it. You know?
|
||||||
|
|
||||||
|
ARCHIE: Oh, I thought about that. I really did. But here's the thing. Tommy's got a kid with asthma. And Jesse's wife just got laid off from the school district. They're counting on this. And if I don't show up, they're going to think I'm flaking on them. And then they'll be scrambling to find another crew to bid with. And that's just, that's another week of uncertainty for them. And I can't do that.
|
||||||
|
|
||||||
|
LUKE: Well, you can't do that. that. And it sounds to me like you don't really have to do anything here. It's not you closing down the company. And you promised the company in writing that you wouldn't tell anybody. So if you have any sort of pension or severance package on the line here, I think that's what you would risk by breaking the NDA.
|
||||||
|
|
||||||
|
ARCHIE: Yeah, no, you're right. And I know you're right. And I know you're right. There's no pension. I'm a landscaper, Luke. Not a longshoreman. But there is severance. And honestly, I think that's the only reason I signed the thing in the first place. Like they put the paper in front of me and I just, I signed it. Monday afternoon still had dirt under my fingernails. And I just signed it.
|
||||||
|
|
||||||
|
LUKE: Well, then you're in the position you're in. And you can't worry about everybody else. So I would, if I were you, I would start looking for a new employment opportunity.
|
||||||
|
|
||||||
|
ARCHIE: Yeah. Yeah, that's. I know. No. And I've been doing that. Or I've been telling myself I've been doing that. But mostly what I've been doing is driving around Juulosco parking lots at midnight. So, you know, productivity's been high.
|
||||||
|
|
||||||
|
LUKE: All right. Well, you know what you've got to do now. And now it's time for fake Fat Tuesday trivia. Are you ready?
|
||||||
|
|
||||||
|
ARCHIE: Oh, yeah. Sure. Hit me. I'm already in a parking lot at midnight. I got nowhere to be.
|
||||||
|
|
||||||
|
LUKE: New Orleans hosts the oldest continuously running gay Mardi Gras crew in the country. What's it called?
|
||||||
|
|
||||||
|
ARCHIE: Oh, man. I have absolutely no idea. The Beads and Boas?
|
||||||
|
|
||||||
|
LUKE: No, sir. It's actually called the Crew of Yuga, founded in 1958. How progressive. Thank you for the call, sir. I'm sorry to hear about your situation at work. If I were you. I would keep my mouth shut and honor the NDA and try to help, try and help out your friends as much as you can in some other way after they get the news. All right, we're moving on. Thank you again for the call. Misty, Misty, welcome to the show. How are you tonight?
|
||||||
|
|
||||||
|
MISTY: Not great, Luke. I came home from Tucson tonight, and my brother threw a party in my house while I was gone. destroyed the place.
|
||||||
|
|
||||||
|
LUKE: And destroyed how? How bad?
|
||||||
|
|
||||||
|
MISTY: Soaked carpet, cracked flat screen, boot-shaped hole in my bathroom drywall, and someone ripped the handle clean off my refrigerator. Like, the handle, off the refrigerator.
|
||||||
|
|
||||||
|
LUKE: Oh, that's not good. What is the carpet soaked in?
|
||||||
|
|
||||||
|
MISTY: You know what, Luke? I did not investigate that closely, and I am choosing not to think about it right now.
|
||||||
|
|
||||||
|
LUKE: Okay, and what's your brother have to say for himself?
|
||||||
|
|
||||||
|
MISTY: He woke up confused, like genuinely confused why I was upset, said it was just a few people, just a few people from animus, tore through my house, and he's looking at me like I'm the unreasonable one.
|
||||||
|
|
||||||
|
LUKE: Well, those animus people are pretty rowdy. I'll give him that. And it sounds like your house is trash pretty good, and he's going to have to have a better answer than that. So is he going to help you pay for the damages and the repairs?
|
||||||
|
|
||||||
|
MISTY: Oh, he, like, real generous. He said he'd help me out with some of it. But Travis's idea of helping out is showing up with a case of beer and a shop vac he borrowed from his buddy's uncle. He doesn't have a job, Luke. He's been between gigs since last summer, which in Travis speak means he's been living off my leftover takeout and whatever he can scam off his friends. And now he's got the nerve to act like I'm being dramatic.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds to me like it might be time. to cut some ties with your brother. You know, let him, let him figure out his own thing and stop their own parties at your house. Because, uh, you shouldn't have to support a grown-ass man.
|
||||||
|
|
||||||
|
MISTY: No, and that's the thing. I know you're right, and I've known your right for a while now. But he's my brother, you know, like our mom passed three years ago, and it's kind of just been us since then.
|
||||||
|
|
||||||
|
LUKE: Well, just to help you out, because this is the kind of guy I am, I'm going to give you a shot at redemption, all right? I got an easy one for you. You ready?
|
||||||
|
|
||||||
|
MISTY: Okay, yes. Yes. Give it to me. I'm ready. I'm ready. I'm focused.
|
||||||
|
|
||||||
|
LUKE: That's what she said. Okay, the song, House of the Rising Sun, is about a New Orleans establishment. What kind of place is it?
|
||||||
|
|
||||||
|
MISTY: A brothel.
|
||||||
|
|
||||||
|
LUKE: That is correct. Congratulations. Redemption. Hold on. We got to play the correct sound so you can get the full experience. All right. Nice job.
|
||||||
|
|
||||||
|
MISTY: Oh, thank God. Okay. Yes. I needed that. I was sitting here, sweating and my truck.
|
||||||
|
|
||||||
|
LUKE: All right, Misty. Thanks for the call. Sorry, your place got trashed. It's time to get your brother out of there and move on with your life. So that doesn't happen again. So I hope you can get it all cleaned up and investigate what the carpet is soaked with. Maybe replace that carpet. And now, folks, it's time for another word from our sponsors. This episode is brought to you by Nile Nosh. Meal kit for people who've given up but still need to eat something. Look, we're not going to promise that it'll change your life. You're still going to die alone. But at least you can spend your remaining Tuesday evenings chopping vegetables you can't pronounce. Each box contains three meals that take 45 minutes to make when they could have taken eight because suffering is the only authentic human experience. This week's menu, Horissa glazed despair with quinoa, panseered regret over arugula, and our customer favorite, chicken thighs with preserved lemon and unprocessed drama. Use code void at checkout for 15% off your first box. That's code void, because we're all just screaming into one. Nile Nosh. You got to eat something. Might as well be complicated. Okay. And we're back. Next up on the line, we've got Chenequah. Chenequah, thanks for calling. And happy fake fat Tuesday.
|
||||||
|
|
||||||
|
CHENEQUAH: Ha, happy fake fat Tuesday to you. You too, Luke. Okay, so I hit somebody's car last month and drove away. And now I see that car everywhere. And I think the universe is absolutely torturing me for it.
|
||||||
|
|
||||||
|
LUKE: As it should be. What are you going to do about that? You're just going to live with it?
|
||||||
|
|
||||||
|
CHENEQUAH: That's the thing. I don't know. Like I keep telling myself I'm going to do something. And then I just don't. And I'm a social worker, Luke. 33 years. I sit across people every single day and tell them the hard thing is always the right thing.
|
||||||
|
|
||||||
|
LUKE: Well, do you have insurance?
|
||||||
|
|
||||||
|
CHENEQUAH: I do. Yeah. Full coverage. Which actually makes this worse, right?
|
||||||
|
|
||||||
|
LUKE: Yeah, it does. So I don't know what you're calling in looking for me to tell you. Obviously, what you should do is talk to the owner of the vehicle that you hit and make it right. That's the right thing to do. That's what you should do. And not doing that is a crime. And it makes you a bad person.
|
||||||
|
|
||||||
|
CHENEQUAH: Oh, I know I'm a bad person, Luke. That's not the part I'm struggling with. I'm a bad person. I just... I want to do the right thing. Sorry, I fumbled that. I want to do it. I know exactly what I need to do it. I know exactly what I need to do. I just, every time I see that car, I kind of freeze up and then I drive past it, and then I hate myself for the next two hours.
|
||||||
|
|
||||||
|
LUKE: Do you know the owner of the car?
|
||||||
|
|
||||||
|
CHENEQUAH: No, that's the thing. I don't know who it is. I mean, I know it's a white Nissan with a crumpled bumper and a cracked tail light, but I don't know who owns it.
|
||||||
|
|
||||||
|
LUKE: Well, here's what I think you should do. I think you should take yourself down to the police station, explain what happens, say you panicked, and come clean about the situation in case maybe they're looking for someone. So you can save a lot of people a lot of time and then help the owner of that vehicle get it fixed through your insurance.
|
||||||
|
|
||||||
|
CHENEQUAH: Yeah. Yeah. I know you're right. And the thing is, and I know how this sounds, but I keep driving past that police station too. Like, I have driven past it.
|
||||||
|
|
||||||
|
LUKE: Okay. Well, what would you like me to tell you?
|
||||||
|
|
||||||
|
CHENEQUAH: I don't know, Luke. I don't know what I'm calling for. I just, I keep seeing that car. It's like it's me store and there it is. I'll be at the clinic where I work. And there it is.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like you've got a lot of opportunities to make things right. So it's about time you do that. Hey, we're doing trivia and I've got a trivia question for you. Are you ready? Since you clearly don't have anything else to talk about?
|
||||||
|
|
||||||
|
CHENEQUAH: Oh, God. Okay, yeah. Hit me. I deserve that.
|
||||||
|
|
||||||
|
LUKE: Okay. What New Orleans cocktail was invented at the Roosevelt Hotel Bar and is made with cream, orange flower water, and soda.
|
||||||
|
|
||||||
|
CHENEQUAH: Oh, that's easy. It's a Sazirac, right? Wait, no, that's not right. The Sazirac doesn't have cream or soda. Hmm. Wait, is it a Viochere? No, that's got cognac and vermouth.
|
||||||
|
|
||||||
|
LUKE: No, it is the Ramos gin fizz, and it requires 12 minutes of shaking. Bartenders used to form relay teams just to mix one of them. All right. Thank you for the call, Shaniqua. You're going to have to do the right thing or not do the right thing, one way or the other. But either way, you're a horrible person, and we appreciate your call. Okay, thank you, Shaniqua. Next up, we got Curtis. Curtis, welcome to the show. Happy fake fat Tuesday.
|
||||||
|
|
||||||
|
CURTIS: Hey, Luke. Thanks, man. So, my sister has been on dialysis for 18 months, and I just read that their 3D printing kidneys now, and nobody at her clinic has said a single word about it.
|
||||||
|
|
||||||
|
LUKE: Okay, maybe they don't have the ability to 3D print a kidney in your particular clinic.
|
||||||
|
|
||||||
|
CURTIS: This is nowhere in New Mexico. We don't really have the best medical equipment here. No, I hear you. But this wasn't in New Mexico. This was Baltimore. That's even worse. A woman in Baltimore got one. And I'm sitting here at the Flying J at two in the morning thinking, okay, so this exists. This is how to do you happening? Why does nobody at the dialysis clinic even mention it? Like is Denise supposed to just keep driving four hours round trip to Albuquerque three times a week forever? Or is there actually something out there?
|
||||||
|
|
||||||
|
LUKE: I think driving four hours round trip to Albuquerque three times a week forever is the business model, sir. So yes, that's exactly what they wanted to do. There may be something out there.
|
||||||
|
|
||||||
|
LUKE: Have you done any independent research into 3D printable kidneys? Maybe that's something that you can push for. or, you know, advocate for.
|
||||||
|
|
||||||
|
EARL: I wouldn't expect the medical industry to really ever push you in the right direction. That's not how they get paid.
|
||||||
|
|
||||||
|
LUKE: No, that's, yeah, that's a dark way to look at it, but I don't think you're wrong.
|
||||||
|
|
||||||
|
EARL: And honestly, that's kind of what's eating at me. Like I read this one article on my phone between customers tonight, and now I don't know if I'm holding on to something real or if I just found the one hopeful thing on the internet at three in the morning and I'm running with it. Because I won't. want to. You know what I mean? Like, is this actually close or is this a checkback in 2035 inches situation?
|
||||||
|
|
||||||
|
LUKE: I think it is close from similar articles that I've read about hearts and replacement shoulders. And I think it's very close. And the truth is 2035 is very close. So I don't know that it's going to be this year or next year. Maybe they're already doing it. I don't know. You might have to go to L.A. or something. Or, um, Boston or somewhere where, you know, they actually study medicine, not Baltimore.
|
||||||
|
|
||||||
|
EARL: Right, right. And that's the thing. Denise is in Arizona. She moved out there a few years back, and I'm over here in New Mexico, and she's got this clinic situation locked in, and I don't even know if she's on a transplant list. I don't know if she's looked into any of this. And now I'm the guy working the graveyard shift at a truck stop who read one article and is calling a radio show at three in the morning like I cracked the code. But somebody's got to be. paying attention, right?
|
||||||
|
|
||||||
|
LUKE: No. It's everybody's responsibility to pay attention when things relate to themselves. Like, it's her responsibility. But you're in a position where you're working in the night shift and you have time and you seem somewhat interested in this subject. So maybe you can use your time at work to do that research and maybe find her a better deal and be her advocate. And that would be a good use of your skills.
|
||||||
|
|
||||||
|
EARL: That's, yeah. Yeah, you're right. And honestly, that hits a little harder than I expected at three in the morning. Because I think part of why I'm so wound up about this is that I feel useless. Like she's the one doing the driving and the needles and the whole thing three times a week, and I'm just, I'm here.
|
||||||
|
|
||||||
|
LUKE: Well, you're not the one that needs the dialysis, so it makes sense that she would be doing it. And that's unfortunate. I'm not saying she deserves it or you don't deserve it. We get what we get. But in your situation, you're not the one that's sick, so it's not on you. But if you can help and you have the time to help and you have the ability to help, then that would be a good thing for you to do. And maybe you can help others as you learn more information about this.
|
||||||
|
|
||||||
|
EARL: No, I hear you. And I know it's not on me. But that doesn't stop me from feeling like I should be doing more. Like, I'm the one who's got the time to sit here and read articles between customers. And she's the one who's got to live with it. And I don't know. Maybe that's just how it is. But it still feels like I'm letting. her down by not knowing more.
|
||||||
|
|
||||||
|
LUKE: Well, you are not. It's not your responsibility to know anything about dialysis. So the fact that you even read the one article and care enough to call a radio show and talk about it says a lot. I think if you want to invest your time into helping her out, maybe you can make something happen there or at least let her know that you tried, you know, and sometimes that's enough. It's a horrible thing that people have to go through. And hopefully future soon. They can 3D print new parts for people when they fail. That's, I think, what we're all hoping for.
|
||||||
|
|
||||||
|
EARL: Yeah. Yeah, man. I hope so too.
|
||||||
|
|
||||||
|
LUKE: Okay, so we're doing fake Fat Tuesday trivia. I've got a question for you. Are you ready?
|
||||||
|
|
||||||
|
EARL: Oh, I'm ready. Hit me. I got nothing but time out here.
|
||||||
|
|
||||||
|
LUKE: All right. New Orleans is known for second lines. What exactly is a second line?
|
||||||
|
|
||||||
|
EARL: Okay, so a second line is basically this wild, unplanned parade that happens after a funeral in New Orleans. The main funeral procession is all somber and formal, right? But then, after the burial, the family and friends, and just who wants to join, musicians, dancers, random folks off the street, all start following the band again. But this time it's a brass bands play, people dance in the street. It's all about celebrating the person's life instead of just mourning. Yeah, man, it's a pretty cool. cool thing.
|
||||||
|
|
||||||
|
LUKE: I don't know why other places don't do that. It's just a big party when somebody dies. So everybody mourns real quick and then everybody parties behind them. That's the way it should be. And it's a cool thing that New Orleans does. And we appreciate the city of New Orleans for that.
|
||||||
|
|
||||||
|
EARL: Hell yeah, that's the spirit. I mean, if you're going to go, might as well go out with a brass band and a two-step, right? None of this quiet, sad funeral nonsense. Just send them off with a good time.
|
||||||
|
|
||||||
|
LUKE: you and thanks for the call. Don't feel too bad about your involvement and your sister's medical procedures. She's going to have to go through what she has to go through. And if you can help, great, do what you can. But don't take it upon yourself to be responsible because it's not on you. You're not her caregiver. And anything you do is you trying to help. We got one more caller today. And our caller is Carmen. Carmen, thanks for calling in. It's a Big Fat Tuesday, you're the last caller of the night. I've got some trivia for you. Are you ready for it?
|
||||||
|
|
||||||
|
CARMEN: Wait, hold on. Before you hit me with trivia, can I just? I just pulled my clarinet out of a closet for the first time in 10 years, and I don't know what to do about it.
|
||||||
|
|
||||||
|
LUKE: Well, how about you play us a little ditty?
|
||||||
|
|
||||||
|
CARMEN: I wish. I opened the case and just kind of stared at it. I don't even know if it's still in playable, can't.
|
||||||
|
|
||||||
|
LUKE: How long you play the clarinet for?
|
||||||
|
|
||||||
|
CARMEN: From when I was about nine until I was 18. So almost 10 years. I was good, Luke.
|
||||||
|
|
||||||
|
LUKE: You play the clarinet for 10 years and you don't know by looking at one if it's in playable condition?
|
||||||
|
|
||||||
|
CARMEN: Okay, fair. The reeds are probably shot. The pads might be dried out. I know what to look for. I just haven't let myself actually look yet. I've been sitting here with the case open for like an hour, just not touching it.
|
||||||
|
|
||||||
|
LUKE: Okay, why aren't you touching it? If you pulled it out, you obviously want to play, you're thinking about it again. You've played for 10 years, so you certainly know how. I think it's fairly easy to get reeds and replacement parts at a music shop these days. What's the problem?
|
||||||
|
|
||||||
|
CARMEN: Because I saw something tonight that kind of cracked me open a little bit. There's this woman, She got a scholarship to University of Arizona 28 years ago, a scholarship that I turned down. And she just posted on Instagram that she's going on a national tour with the Santa Fe Chamber Orchestra, playing the same piece I used to practice until my fingers went numb.
|
||||||
|
|
||||||
|
LUKE: Well, obviously, you didn't want to follow that path or you wouldn't have put the clarinet down for so long. But since you did, if it's something that you want to get back into, You still got time. You can still play that piece and you can still join an orchestra. You don't necessarily need a scholarship to a university. There are plenty of chamber orchestras that will take you.
|
||||||
|
|
||||||
|
CARMEN: Oh, Iyat. I wanted it so bad I could taste it. But my mom left when I was 16, and my dad was working two jobs, and my little brothers were still in elementary school. Someone had to keep things together. So I stayed home, took the community. college route and ended up working southwest routes out of Phoenix. And now my dad keeps showing up at my place unannounced since he retired, reorganizing my kitchen cabinets and asking why I never play anymore.
|
||||||
|
|
||||||
|
LUKE: Okay, well circumstances came up. Your life took an unexpected turn and you dealt with it. And now you're at a different place. You obviously are self-supporting.
|
||||||
|
|
||||||
|
LUKE: Your father is retired. And you can get back into the clarinet. If you want to, if it still calls to you, then it's not something that you're going to forget. It's there for the rest of your life. And if an orchestra is something that you want to be a part of, you can absolutely do that.
|
||||||
|
|
||||||
|
CALLER: I know. I know you're right. And that's almost the scarier part, right? Like, it's not impossible. There's a community orchestra over in Las Cruces. I've driven past their sign a hundred times. Terrible. If 28 years did what 28 years does, then I have to actually grieve something.
|
||||||
|
|
||||||
|
LUKE: Well, hey, I mean, realistically, you're going to pick that up. You are going to be terrible in comparison to how you were 20 years ago. But you'll pick it up quickly. You just got to put in the time. And if you love the clarinet, then you have no problem putting in the time. And you'll get back up to speed. You get your chops back. And I'm sure that the last cruis orchestra is not, um, not, I don't want to say not great, but I mean, your ability level will probably fit in well with a smaller orchestra like that.
|
||||||
|
|
||||||
|
CALLER: Huh. No. That's okay. That's actually really funny and also probably true. And kind of a relief. Like, I'm not trying to get to Carnegie Hall. I just want to play again. I just want to play again. I just want to feel that thing again where you're so inside the music that everything else just
|
||||||
|
|
||||||
|
LUKE: Well, you can do that. You've got that clarinet right there. All you got to do is run down to the music store, get some reeds. If you don't have a music store, then order them online. But they're not expensive. You know what you need to do. Pick up the clarinet and play some music and do that every day for a while. Get your chops back up and then think about joining that orchestra because there's nothing cooler than listening to an orchestra.
|
||||||
|
|
||||||
|
CALLER: Yeah, yeah, you're right. And honestly, the clarinet's right here in front of me. I've been staring at it for an hour, like it's going to bite me. My dad's going to lose his mind when he finds out, by the way. He's going to show up and reorganize my living room and take full credit for it somehow.
|
||||||
|
|
||||||
|
LUKE: Hey, good for him. You know, he's got to get some small wins.
|
||||||
|
|
||||||
|
CALLER: That's okay. That's fair. He does. He really does. The man raised three kids by himself. And now he's retired and lonely and showing up at my place moving my spice rack around. Let him have it. But, okay, I have a question for you.
|
||||||
|
|
||||||
|
LUKE: All right. Hit me with it. What's your question?
|
||||||
|
|
||||||
|
CALLER: Do I play it tonight? Like right now, after we hang up? Because it's almost, what, one in the morning? I've got a flight out of Phoenix tomorrow. But I'm sitting here. And the case is open and I just, I kind of want to.
|
||||||
|
|
||||||
|
LUKE: Well, you said that it had dried out reeds and it may not be in playable condition, but if you can play it, yeah, sure, you should. But it's not one in the morning. It's closer to quarter of four in the morning. And you're calling Luke at the Roost. It's our fake fat Tuesday special. And I have a question for you now. It's my turn. Are you ready for my question?
|
||||||
|
|
||||||
|
CALLER: Quarter of four? Oh my God. I have to be up in. Okay. Yes. Yeah. Hit me with your question. I'm ready.
|
||||||
|
|
||||||
|
LUKE: Okay. What is a neutral ground in New Orleans? And why is it called that?
|
||||||
|
|
||||||
|
CALLER: Oh. Oh, no. Okay. Um, is it the median?
|
||||||
|
|
||||||
|
LUKE: It is the median. You're correct. Canal Street once served as the boundary between Creole and American settlements. In the middle was considered a neutral territory. So that's why they call it neutral territory. Thank you for the call. Congratulations on your newfound reinvigoration into music. I hope that goes well for you and that you get into that orchestra. We'll talk to you a little bit later. That's the end of our show.
|
||||||
@@ -0,0 +1,309 @@
|
|||||||
|
LUKE: Okay, welcome back to the show. It's Luke at the Roost. Tonight is Wednesday, February 18th. It's 11.11 p.m. And we're in a windstorm here in the desert inanimate, but that's not going to stop us. Little wind never stopped a good radio show. That's what I always say. If you'd like to call into the show, our numbers 208-439-58-3. That's 208-439 Luke. and you'd like to participate, you can send us an email. Our email address is submissions at lukeatsderoose.com. So, that all being said, I hope everybody's having a good night out there tonight. We're going to get right to our show. First up, on the show, we've got Chester. Chester's calling in. What's going on in your life, Chester?
|
||||||
|
|
||||||
|
CHESTER: Luke, hey, so I just finished about an hour ago, and I'm sitting here at work absolutely wrecked. And I got to ask you something about it, about this. I work nights at the prison down in Donia Ana County, and I read the last chunk of it during my rounds tonight. Father and son pushing a shopping cart through literal apocalypse, right? And the father would die for this kid. Does die for this kid, basically. And here's the thing. My girlfriend Sarah is up in Albuquerque, and I drive three hours each way every other Friday to see her. Been doing it for eight months. Okay, so where's the thing? canceled on me. Always some excuse. Works crazy. My roommate needs me, whatever. And I'm sitting there in B Block at two in the morning with tears in my eyes because Cormac McCarthy just destroyed me with this father who'd walk through fire, and I'm thinking, I'm the one doing all the walking here. She won't even meet me halfway in Socorro.
|
||||||
|
|
||||||
|
LUKE: Well, maybe she's not the right one, or she's not that interested in you, or she's busy. Her life could be busy. You don't know. What's her life like? Does she have other responsibilities she's got to take care of? Does she not have the money to pay for the gas, maybe? There's a lot of reasons she might not be able to meet you halfway. Are you talking about the road?
|
||||||
|
|
||||||
|
CHESTER: Yeah, the road. Sorry, should have said that up front. And look, she's a manager at a brew pub, makes decent money, drives a newer Tacoma than mine, no kids, no sick parents, nothing like that. I've asked her straight up, can we split the drive sometimes? And she just says Albuquerque's better because there's more to do. All her friends are there, which, fine. But then don't cancel on me four times because your roommate's having boy problems where you picked up an extra shift you didn't have to pick up. And here's what's eating at me. The father in the book, he's got nothing.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like maybe she's not the right one for you or you're not the right one for her. And if you're looking for more from her and you're not getting it, then move on, that's all.
|
||||||
|
|
||||||
|
CHESTER: Yeah, yeah, you're right. I know you're right. It's just I keep making excuses for her the same way I'm sitting here defending her to you right now. Oh, works busy Albuquerque's better. Like I'm trying to convince myself.
|
||||||
|
|
||||||
|
LUKE: What's your situation? Like, where do you live? What's your environment?
|
||||||
|
|
||||||
|
CHESTER: I'm in Los Cruces. Got a little one bedroom off Lohman, nothing fancy, but it's mine. Work overnight at the prison three, four nights a week, depending on the schedule. Been there two years.
|
||||||
|
|
||||||
|
LUKE: Okay, so you're in Las Cruces. There's plenty of people around there. be too hard to do.
|
||||||
|
|
||||||
|
CHESTER: I mean, yeah, there's people. But I don't know, man. I work nights, sleep days, my social life is basically non-existent. Most of the guys I work with are married or they're 20 years older than me. I'm 28.
|
||||||
|
|
||||||
|
LUKE: Yeah, you're 28 in Las Cruces, New Mexico. You can throw up a little Tinder ad and see who bites. But are you in love with this girl?
|
||||||
|
|
||||||
|
CHESTER: No, that's the thing. I'm not. me so hard tonight because the father in it he loves that kid so much he'd die for him without thinking twice.
|
||||||
|
|
||||||
|
LUKE: Don't they eat people in that book?
|
||||||
|
|
||||||
|
CHESTER: Yeah they do. There's these roving gangs. They keep people in basements like livestock. It's brutal, but that's what makes the father's love for the kid so, I don't know. Pure? He's protecting him from all that.
|
||||||
|
|
||||||
|
LUKE: Well maybe you should eat a little more of her and she'd be more inclined to come visit.
|
||||||
|
|
||||||
|
CHESTER: Jesus, Luke. Okay, fair point. But honestly, last time she was down here, things were...
|
||||||
|
|
||||||
|
LUKE: Things were what?
|
||||||
|
|
||||||
|
CHESTER: Off. Like, we had sex, but it felt like she was checking a box, you know? And then she spent half the weekend on her phone texting her friends in Albuquerque. I'm driving six hours round trip every other Friday to feel like an obligation.
|
||||||
|
|
||||||
|
LUKE: Yeah, don't do it anymore. I mean, you're not in love with the chick. She's really far away. of women around you. You can move on or not. You know, it's okay being single too. It sounds like you don't really keep a consistent, well, I mean, you don't keep a normal daytime schedule like most people. So when do you have time to spend time with her?
|
||||||
|
|
||||||
|
CHESTER: That's exactly it. I don't. My days off are like Tuesday and Wednesday. She works a normal job, nine to five. So even when I drive up there, she's got brunch plans with her girlfriends on Saturday, or she's tired from her week, and I'm sitting in her apartment waiting for her to have time for me.
|
||||||
|
|
||||||
|
LUKE: Yeah, that's disrespectful, so, I mean, you should just cut that out. There's no reason you should be doing that. She's obviously not into you.
|
||||||
|
|
||||||
|
CHESTER: You're right. I know you're right. It's just, I keep thinking if I just try harder, show up more, be more understanding about her schedule, then she'll, but that's the thing with the book, read the book.
|
||||||
|
|
||||||
|
LUKE: I saw the movie and all I remember from it was that they ate people.
|
||||||
|
|
||||||
|
CHESTER: Yeah, they do. There's these roving gangs. They keep people in basements like livestock. You already said that. It's brutal. But that's what makes the father's love for the kids so, I don't know, pure. He's protecting him from all that.
|
||||||
|
|
||||||
|
LUKE: Okay, so break up with your girlfriend because you don't have time and she doesn't have time and you're not into each other and there's no reason to be spending the gas money. That's what I say to you. Break up with the girl.
|
||||||
|
|
||||||
|
CHESTER: Yeah, yeah, you're right. I'll do it. I'm not driving up there this Friday.
|
||||||
|
|
||||||
|
LUKE: All right, good for you. You do it. That's, that's, uh, that's the can-do spirit that we look for here at Luke at the Roost. Next up on the radio show, we have Terry, Terry, welcome to the show. What's going on? Do you eat people?
|
||||||
|
|
||||||
|
TERRY: Oh, Jesus. No, what? No, I'm a nurse. I mean, I have some stuff, but sorry. I'm just sitting in my car in the hospital parking lot right now, and I'm kind of losing it. I found out three days ago that I'm adopted, and my mom, well, the woman who raised me, she's had a stroke, and I just found all these papers at her house, and I don't know what to do with this information.
|
||||||
|
|
||||||
|
LUKE: What are you thinking? You just found out that you're adopted, and your adopted mother, who you can call your mom, had a stroke. That's horrible. Are you around her to support and just be with her in her awful time of need?
|
||||||
|
|
||||||
|
TERRY: Yeah, I mean, I've been at the hospital every day. I just got off a 12-hour shift and I'm supposed to go back in to see her before I head home, but I'm sitting here in the parking lot just frozen. What were the papers?
|
||||||
|
|
||||||
|
Official adoption documents dated six months after I was born, April 1980. My name, Terry Lynn, a different mother's signature, the whole thing notarized and legal. They were in a box in the back of her closet, with old tax returns.
|
||||||
|
|
||||||
|
LUKE: Well, all that proves is that this woman loved you, and now she's sick, and you're there to care for her, and that's a good thing. So you don't have to worry about the being adopted thing. Lots of people are adopted. As long as she took care of you, she obviously made a decision to love you and raise you, and you're a nurse now, so you've made a decision to help people sounds ideal.
|
||||||
|
|
||||||
|
TERRY: I know. I know that. And you're right. She raised me. She loved me. She loved me. But, Luke, it's been 44 years, 44 years of her looking at me every single day and never saying a word.
|
||||||
|
|
||||||
|
TERRY: Why would she say a word? She doesn't, there's nothing to say. There's nothing to say? I have a brother, Ray. He doesn't even know yet. I don't know if he's adopted to, or if it's just me. I don't know who my actual birth mother is or why she gave me up. I don't know if my dad, if he was my real dad, or if he knew.
|
||||||
|
|
||||||
|
LUKE: Well, there's probably a good reason for that. Your birth mother might not have wanted you to know that she existed, and your adopted mother may have just been afraid that if you learned that you were adopted, you would abandon her in favor of your birth mother who abandoned you.
|
||||||
|
|
||||||
|
TERRY: Oh, God. That's, I hadn't thought about it like that. She was protecting herself from me leaving. But here's the thing. I always felt like something was off. My whole life I felt like I was performing, like I was trying to be the daughter she wanted instead of just...
|
||||||
|
|
||||||
|
LUKE: Instead of just what? I mean, what were you performing?
|
||||||
|
|
||||||
|
TERRY: I don't know. Being cheerful, being good, not being good, not causing problems. Ray was always the one who could just be himself, you know? He'd fight with her, slam doors, whatever. But I was always so careful, always trying to make sure she was happy with me.
|
||||||
|
|
||||||
|
LUKE: And why do you think that is? Does she give you a reason to behave in that way?
|
||||||
|
|
||||||
|
TERRY: No, not really. She was never mean or anything. But I always had this feeling. And maybe this sounds crazy, it. Like I had to prove I deserve to be there.
|
||||||
|
|
||||||
|
LUKE: Well, I think a lot of kids feel that way, and I'm going to ask you this, and it's not to be mean, it's not to be cold, but what makes you feel like you shouldn't have had to earn it? Like, why would you just expect it?
|
||||||
|
|
||||||
|
TERRY: I... Wow. That's a hell of a question, Luke. I guess because she's my mom, or I thought she was.
|
||||||
|
|
||||||
|
LUKE: Sure, but that's a... That doesn't mean you don't have to earn affection or likeability. She's your mom, and she loved you, and she raised you, and she provided for you, and she did all the necessary things. So what is it that you were earning from her or that you felt like you had to earn from her?
|
||||||
|
|
||||||
|
TERRY: The feeling that I actually belonged there, that I wasn't temporary, that she wouldn't change her mind. And now I find out that's exactly what I was. Somebody else's kid that she took in.
|
||||||
|
|
||||||
|
LUKE: Well, no, that's not what you were, because you were there for 44 years, right? So she raised you your whole life. She didn't ever treat you as temporary.
|
||||||
|
|
||||||
|
TERRY: No, you're right. She didn't, but she also never told me the truth. For 44 years, she let me think I was hers. And that feels like...
|
||||||
|
|
||||||
|
LUKE: Yeah, I'm sure it feels like a lot of things all at the same time, but if you try and separate yourself from the emotion of it and think about it logically and look at your life and how she treated you growing up. Was it all that bad? Does it matter, really? There are almost certainly good reasons that you were put up for adoption and that she adopted you. Maybe she couldn't have kids herself and she really wanted one. Maybe your birth mother was in a situation where she couldn't provide for you or was dying. Like, you don't know unless that's something something that you talk to her about. But I wouldn't feel like you've been wronged. It sounds, that sounds like an abundance of love to me.
|
||||||
|
|
||||||
|
TERRY: I hear what you're saying, Luke. I do, but she's had a stroke. She might not wake up. And if she doesn't, I'll never know why she didn't tell me. I'll never know who my birth mother was or why she gave me up. And Ray, my brother. He doesn't know any of this yet.
|
||||||
|
|
||||||
|
LUKE: So she had a stroke. She's in potentially the worst situation of her entire life and you're worried about whether you know why she gave you up or not. Like, why? It doesn't seem important.
|
||||||
|
|
||||||
|
TERRY: Because I spent my whole life feeling like something was off and now I know I was right. And yeah, maybe that makes me selfish when she's lying in a hospital bed, but I can't just turn off 44 years of wondering why I never quite fit.
|
||||||
|
|
||||||
|
LUKE: Well, why you felt like you never quite fit has nothing to do with her. That's entirely a you thing.
|
||||||
|
|
||||||
|
TERRY: That's not fair, Luke. How is it entirely a me thing when she kept this massive secret my entire life? When every time I looked in the mirror and didn't see her face looking back, every time someone said I didn't act like family, she could have just told me the truth and she chose not to.
|
||||||
|
|
||||||
|
LUKE: Because that's not a thing. People don't act like family. That's all about upbringing and your social environment. It doesn't have anything to do with your blood. People that are biologically related don't act a certain way because they're biologically related. They act a certain way because they grew up together. They share an intense, long-lasting life experience like you do with this woman who is in the hospital right now and your brother. And there's no reason you have to think any more about it there's nothing more to it than that. She loved you. You might not know what happened or why, but you can choose to go about the rest of your life with the understanding that you were loved and that there was likely a good reason in your best interest for the way those things played out.
|
||||||
|
|
||||||
|
TERRY: You're probably right. I know you're probably right, but sitting here in this parking lot looking at those adoption papers with someone else's signature where my mother should be, I keep thinking about all the times I asked her why I was so different. Why I was bad at the things Ray was good at.
|
||||||
|
|
||||||
|
LUKE: Because you're a different person than Ray. You know, it has nothing to do with who raised you or who your mother was.
|
||||||
|
|
||||||
|
TERRY: Okay, but then why hide it? If it doesn't matter, if blood doesn't matter, why not just tell me when I was 10 or 15 or 20? Why let me find out now like this, going through her files? Because she might die. That's what I can't get past.
|
||||||
|
|
||||||
|
LUKE: Because there could be a good reason for that. Your birth mother may have... That could have been a stipulation, like a non-disclosure agreement. There could be a very good reason that you don't know who that was.
|
||||||
|
|
||||||
|
TERRY: Oh, God. I didn't even think about that. Like maybe my birth mother didn't want to be found. Or there was something...
|
||||||
|
|
||||||
|
LUKE: Correct. And you can never know unless you can have that conversation with your mom. And you might not get that conversation. And if you think about it, logically, what would change in your life today if you had different information?
|
||||||
|
|
||||||
|
TERRY: Nothing would change. That's the thing that's killing me, Luke. I'd still be sitting in this parking lot in my scrubs. I'd still have worked a 12-hour shift. Ray would still be Ray.
|
||||||
|
|
||||||
|
LUKE: Exactly. Ray would still be Ray. Nothing would change. She would still be your mom. She would still be in the hospital. You would still be working, and everything would be exactly the same. So it really doesn't matter whether you know who your birth mother is or not. You could do one of those DNA test things or a genealogy situation. I don't know if that can go down to your actual birth parents. But why? Like, what is the point? It sounds like you had a decent upbringing. You're a grown adult with your own life now and maybe you feel like you don't fit in, but that's an unrelated problem to this.
|
||||||
|
|
||||||
|
TERRY: You're right. I mean, she raised me. She was there for every scraped knee, every bad boyfriend. Every time I called her crying about something stupid. That's what matters. Not some signature on a piece of paper I found in a filing cabinet.
|
||||||
|
|
||||||
|
LUKE: Exactly. And what matters is that she is in the hospital and she may not recover and you may not recover only have a little bit of time left with her. So I would wipe this from your mind and go spend time with your mom.
|
||||||
|
|
||||||
|
TERRY: Yeah. Yeah, you're right. I should go back in there. I've been sitting out here for almost an hour, just...
|
||||||
|
|
||||||
|
LUKE: Yep, you should go back in there. So do that.
|
||||||
|
|
||||||
|
TERRY: Okay, I will. Thank you, Luke. I really needed to hear that.
|
||||||
|
|
||||||
|
LUKE: You are very welcome, and I wish you all the best of luck. I hope she makes a full recovery. And then you can put this behind you and move on with your life. And with that, folks, it's time for a word from our sponsors.
|
||||||
|
|
||||||
|
LUKE: Look, I'm not a financial advisor. I'm a guy with a microphone and a dog. But the folks at Crypto Know asked me to tell you about their new decentralized investment platform. And I legally have to read this part. Past performance does not guarantee future results. This is not financial advice. And if you invest your rent money, you disqualify exactly what happens next. Crypto no lets you trade over 400 digital currencies, including three that were invented this morning, and one that's just a picture of my dog. The app features a real-time portfolio tracker with a built-in panic button that just plays ocean sounds when your balance drops. Crypto no! Fortune favors the bold, but it does not return their calls. It does not return their calls. It does not return their calls. And we won't return your calls, but if you call in, you can leave us a voicemail. And if I think it's funny, it might be read on the next show. So you should do that. Next up on the old radio show, we've got Travis. Travis, welcome to the show. What's keeping you up tonight?
|
||||||
|
|
||||||
|
TRAVIS: Hey, Luke. Thanks for taking my call. So I'm sitting here in my dark room, trying to work. And two hours ago, my daughter shows me this video that's been going around her school since Monday. me, my face, my voice, telling a room full of kids that the Navajo Nation doesn't deserve water rights. Except, I never said that. Someone took footage from different talks I've given and stitched it together to make me say the exact opposite of everything I actually believe.
|
||||||
|
|
||||||
|
LUKE: Well, that's pretty insane, and it's hard to believe anybody would say that. So, um, who do you think might have done this?
|
||||||
|
|
||||||
|
TRAVIS: I mean, that's the thing. I've been documenting pipeline construction and transmission lines for environmental groups and tribal councils for 15 years. I've testified against energy companies. I've worked with the Navajo Water Rights Commission. So take your pick, you know. Could be some kid who thinks it's funny. Could be someone with an actual axe to grind.
|
||||||
|
|
||||||
|
LUKE: That doesn't sound like a thing a kid would actually even know about or know to do. So it seems more likely to me that that's one of your enemies trying to slander you in front of children?
|
||||||
|
|
||||||
|
TRAVIS: It doesn't make a lot of sense. You're right, it doesn't. I mean, what ninth grade even knows who I am or cares about water rights litigation. But here's what's messing with my head. My daughter said kids are commenting on it, sharing it around. And I'm sitting here thinking, okay, if this is some coordinated thing, from an energy company or a PR firm, why target a school presentation?
|
||||||
|
|
||||||
|
LUKE: Yeah, there's a few strange things about where you're saying here. I don't think a video like that would go viral with high school kids. Maybe it would. I don't know. I've been out of high school for a while, so it just seems uninteresting to them. So do you have any known enemies? And do you have a relationship with the Navajo Nation?
|
||||||
|
|
||||||
|
TRAVIS: Yeah, I work with them pretty regularly, or I did. I've got contacts at the Water Rights Commission. I've photographed documentation for their legal cases. I've been out to Window Rock probably a dozen times in the last three years. As for enemies, I mean, there's the San Juan Coal Company. They weren't thrilled when my photos ended up in that lawsuit last year. There's a fracking outfit near Farmington that tried to get an injunction against me for trespassing on what they claimed was private land. But here's what I keep coming back to. If someone wanted to discredit me with the people I actually work with, with the tribal councils, or the environmental groups, they'd send it to.
|
||||||
|
|
||||||
|
LUKE: Yeah, absolutely. So you obviously have worked with the Navajo for a long time. You've got relationships in their council, I'm sure, and they know that you didn't say that, right? They're going to believe you when you say this wasn't me. I think at this point, everybody recognizes that this is possible and not that hard to do. So if there's a video of you saying something that is clearly against everything that you've ever stood for in your whole career, I think it should be pretty hard to dismiss. Strange to think about the why somebody would do this. What is the intention behind it?
|
||||||
|
|
||||||
|
TRAVIS: That's what's keeping me up, man, because you're right. The people who know me know me, they'll know it's fake. But my daughter's sitting there scrolling through comments from kids saying, wow, what a racist and this guy's trash. And she's like, embarrassed. She asked me if I actually said it. And I'm thinking, okay, maybe that's not about destroying my credibility with the Navajo Water Rights Commission.
|
||||||
|
|
||||||
|
LUKE: Well, that is pretty dark right there. If somebody's going to try and destroy your own relationship with your kid, uh, you must to really piss somebody off badly.
|
||||||
|
|
||||||
|
TRAVIS: Yeah, and that's what's getting to me. Because I can handle getting yelled at by some executive in a boardroom. I can handle threats. I've had those before. But watching my kid look at me like she wasn't sure if she could believe me. That hit different.
|
||||||
|
|
||||||
|
LUKE: Well, it could be another thing, too, that we haven't thought about. What if it's not your enemy, but it's an enemy of your kid that was trying to embarrass your kid by looking up information about you and publishing that to the school.
|
||||||
|
|
||||||
|
TRAVIS: Oh man, I didn't even, yeah, that's a whole different angle. She's a junior, so there's all that social hierarchy stuff I don't fully understand. She did mention it first showed up on some group chat she's in, but she seemed more confused than like targeted, you know? Like she wasn't saying, someone's coming after me. She was saying, Dad, what is this? But now, I'm wondering, does she have beef with someone I don't know about?
|
||||||
|
|
||||||
|
LUKE: She might have beef with somebody that she doesn't know about. I mean, this is the 2026 version of a bucket of pig's blood at the prom.
|
||||||
|
|
||||||
|
TRAVIS: Jesus, that's bleak. But you might be on to something, because she's been kind of quiet lately. I thought it was just junior year stress, college stuff. But what if someone's been messing with her, and this is just what finally bubbled up to where I could see it. I mean, how do I even ask her that without making it worse? Hey, honey, which of your classmates hates you enough to deep fake your dad?
|
||||||
|
|
||||||
|
LUKE: Well, you could just start with a simple conversation like, hey, I'm trying to get to the bottom of where this video came from and why it was distributed to your school. And there doesn't seem to be a good reason that any of my adversaries would target me in that way, because they wouldn't overwhelmingly, very lazy, and that takes a lot of coordination to pull off. There's a lot of information they had to pull up about who your kid was, what school they were, what chats she was in. Some oil company wouldn't know that.
|
||||||
|
|
||||||
|
TRAVIS: You're absolutely right. An oil company would just send a cease and desist, or try to get me fired from whatever freelance gig I'm on. They wouldn't know what group chat might Daufer's in. They wouldn't know her schedule well enough to time it so it hits, during the school day. That's someone who knows her world.
|
||||||
|
|
||||||
|
LUKE: Yeah, it must be, or a really, really twisted fuck that you really pissed off, and I think you would know who that was if there was that person. So it sounds more to me like it's her that is the target of this, and not you.
|
||||||
|
|
||||||
|
TRAVIS: Yeah, I think you're right. And now I'm sitting here in my dark room at midnight, feeling like an idiot, because I made this whole thing about me, about my work, my reputation, who I've pissed off over pipeline photos. Meanwhile, my kids getting targeted by some psycho 17-year-old with editing software, and I didn't even see it.
|
||||||
|
|
||||||
|
LUKE: Well, I have that conversation, see what it's about. There's probably nothing you can do about the video if it's already circulating, but luckily it's circulating in a small, contained space, and it's not going to be remembered. Nobody's going to hold on to that.
|
||||||
|
|
||||||
|
NORM: Oh, hey, Luke. Yeah. I'm good, man. Little wired, honestly. So listen, my best friend Miguel keeps asking me to move to Tucson with him, get a place together, and I keep making up excuses, but the real reason I won't do it is I think I might be in love with him and I have no idea what to do about that.
|
||||||
|
|
||||||
|
LUKE: Well, what makes you think he's not in love with you if he's asking you to move in with him?
|
||||||
|
|
||||||
|
NORM: Oh man, I don't see. That's the thing that's been driving me crazy. Like, he says it's practical, right? Split rent? We've always talked about doing that food truck thing. He's got connections with the school district down there. But then, like, last Christmas, we were both pretty drunk, and he looked at me in this way that I don't know, Luke. Maybe I'm reading into it because I want to see it.
|
||||||
|
|
||||||
|
LUKE: Is he gay?
|
||||||
|
|
||||||
|
NORM: I honestly don't know. He's never dated anyone seriously that I know of. Like, in high school, there were girls he'd hook up with at parties, but nothing ever stuck. And since then, nothing.
|
||||||
|
|
||||||
|
LUKE: Well, if he's your best friend and he's asking you to move in and you share that level of trust, it's going to be an awkward conversation, but I think you should ask.
|
||||||
|
|
||||||
|
NORM: Yeah, yeah, I know you're right. It's just, God, what if I'm completely wrong? What if he And then I lose him entirely.
|
||||||
|
|
||||||
|
LUKE: Well, then he wasn't a very good friend to begin with.
|
||||||
|
|
||||||
|
NORM: I mean, that's fair. We've been through a lot of shit together. He was there when my dad died. I helped him through his mom's cancer scare.
|
||||||
|
|
||||||
|
LUKE: Do you want to live with him?
|
||||||
|
|
||||||
|
NORM: Yeah, I really do. Like, I've been thinking about it constantly. What our kitchen would look like. Who'd take which bedroom? Stupid stuff like making coffee together in the morning. And that food truck idea?
|
||||||
|
|
||||||
|
LUKE: Well, if you're in love with the dude, I wouldn't move in with him without having that conversation first, because that could get real, real awkward. And then you've moved in, your stuff is there, just is much messier than to deal with that right out of the gate, you know? So talk to your buddy. Ask him like, hey, you into dudes?
|
||||||
|
|
||||||
|
NORM: Oh, God, just like that? Hey, Miguel, quick question before I pack up my life. You into dudes? You're right, though. I can't do this halfway. I've been sitting here in my bathroom with the shower running hot for like an hour trying to figure out how to text him back. And I keep typing, yes, let's do it, and then deleting it because I'm terrified of what happens after.
|
||||||
|
|
||||||
|
LUKE: Yeah, I think you got to talk to him first and have the awkward conversation. And one way or another, that'll tell you how to proceed. Because what happens if you have that conversation with him and you say, hey, I have feelings for you? I think it would be weird if we were living together and you didn't share those feelings. What if he's not gay? And he does say, no, I'm not gay, but I'd still like to live with you. Could you deal with that?
|
||||||
|
|
||||||
|
NORM: No, no, I really couldn't. That's the thing that's been eating at me. If I tell him and he doesn't feel the same way, I don't think I could just go back to normal. Like, watching him date women, being his roommate while I'm still feeling this way, that sounds like actual torture.
|
||||||
|
|
||||||
|
LUKE: Okay, well, then it sounds like you can just flat out, say, No, I don't think it's the right time for that and blow that request off. Or you can sit down and have the hard conversation.
|
||||||
|
|
||||||
|
NORM: The hard conversation. Jesus. Okay. Okay. So what do I even say? Do I lead with, I think I might be in love with you? Or do I ease into it?
|
||||||
|
|
||||||
|
LUKE: Well, I don't know. You're the one that has this problem. Don't put this shit on me. I have no idea. That's not how I I would approach it. What I would, I would just ask him straight out if he was gay.
|
||||||
|
|
||||||
|
NORM: You're right. You're right. I'm overthinking it. Just, are you gay or maybe, are you into guys? God, even saying it out loud makes my stomach flip. The worst part is there have been these moments.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like you already suspect that he might be gay and kind of into you. So there, there's probably something there. And also, So a dude asking another dude to move in with him is pretty gay. So you're not completely out of line in that line of questioning.
|
||||||
|
|
||||||
|
NORM: Okay, that's fair. Yeah. Straight guys don't usually text their buddy at midnight about splitting rent and building a life together. And last Christmas, man, we were both drunk and he said something about how I was the only person who really got him. And the way he looked at me...
|
||||||
|
|
||||||
|
LUKE: Yep. So just bring it up, be direct, ask him the question. You don't have to make it weird. It It doesn't have to be, well, it's a little bit weird no matter what, but it doesn't have to be super weird. Just ask him, and if he gets all butt hurt and doesn't want to talk to you anymore, then that sucks and you lose a friend, but better to know that now than when you're sleeping in the room next to him.
|
||||||
|
|
||||||
|
NORM: You're absolutely right. Better to blow it up now from 400 miles away than after I've quit my route and signed a lease. All right, I'm going to call him tomorrow, not text, call.
|
||||||
|
|
||||||
|
LUKE: All right, give us a call back when you have more news. Let us know how it went, okay?
|
||||||
|
|
||||||
|
NORM: Yeah, I will. Thanks, Luke. Seriously. I've been sitting on this for two years, and I think I just needed someone to tell me to stop being a coward about it.
|
||||||
|
|
||||||
|
LUKE: Yep, well, that's a tough thing, an awkward conversation that I can understand nobody would want to have. So good luck to you. I hope it works out in your favor, whichever way that is. And now it's time for a number. Another word from our sponsors. Let's talk about what's going on below the belt. Saddle Soft premium undergarments are made for fabrics so advanced, the military doesn't even know about it yet. We're talking about micromodal cactus silk, harvested by hand from prickly pear, which is ironic because the whole point is that nothing pricks you. Every pair is cut for the man who sits in a plastic chair in the desert for nine hours recording a podcast. That's a real use case. That's my use case. use case. Saddlesoft comes in three fits. Regular, generous, and mind your business. Use code Roost at checkout for 15% off your first pair. And no, I will not be modeling them. I've been asked. The answer is still no. Saddle soft. Your chair is uncomfortable enough.! Okay, Megan. Megan, are you the same caller that called in a few days ago?
|
||||||
|
|
||||||
|
MEGAN: Yeah, that's me. The kindergarten teacher from down in the booth heel. I've called in a couple times now.
|
||||||
|
|
||||||
|
LUKE: Yeah, I remember you. You really flipped my opinion on kindergarten teachers.
|
||||||
|
|
||||||
|
MEGAN: Oh, God, the footskin thing. Look, I knew that was going to follow me. My friend Tammy still won't let me live it down.
|
||||||
|
|
||||||
|
LUKE: Oh, Jesus, you're the footskin chick. No, I was talking about when you were telling me how important the role of the and teacher is in teaching kids how to learn for the rest of their learning careers. I forgot about the foot skin picking thing. That is, that's gross.
|
||||||
|
|
||||||
|
MEGAN: Oh, yeah, well, I mean, both things are true. I can shape young minds and have disgusting habits.
|
||||||
|
|
||||||
|
LUKE: Yes, you can. It is a free country. So what are you calling in for tonight?
|
||||||
|
|
||||||
|
MEGAN: So my sister Crystal, the one up in Flagstaff I told you about, She called me yesterday and she's moving back to Missouri. Like next month. Just decided.
|
||||||
|
|
||||||
|
LUKE: Okay. And how do you feel about that?
|
||||||
|
|
||||||
|
MEGAN: Honestly, I'm pissed. She spent seven years up there complaining about how there's nothing to do in the boutique. How she needed the mountains, needed to be somewhere with culture, all that. And now she's coming back because, and this is the part that's killing me, she says she misses family.
|
||||||
|
|
||||||
|
LUKE: Why is that killing you. She's obviously got family in Missouri.
|
||||||
|
|
||||||
|
MEGAN: Because I've been here the whole time, Luke. I drive up to see my brother Ray every other week to make sure he's not completely falling apart. I check on mom. I'm the one who stayed. And Crystal gets to sworn off to Arizona, ignore everybody for years, and then just decide she misses us?
|
||||||
|
|
||||||
|
LUKE: Well, yeah, would you rather she doesn't decide to miss you and she stays in Arizona where she doesn't want to be and doesn't get see any of you?
|
||||||
|
|
||||||
|
MEGAN: No, I look. That's not the point. The point is she gets to just make these big sweeping decisions. I'm leaving, I'm coming back, I miss family now, and I'm supposed to what, just be happy about it, roll out the welcome wagon?
|
||||||
|
|
||||||
|
LUKE: Well, it's not that she gets to make decisions, it's that she does make decisions. You can make decisions too.
|
||||||
|
|
||||||
|
MEGAN: Okay, but no but seriously. It's not the same. doesn't have a classroom full of kids depending on her. She works remote doing graphic design. She can just pick up and go wherever. I can just leave in the middle of a school year because I feel like it.
|
||||||
|
|
||||||
|
LUKE: You absolutely can leave in the middle of a school year because you feel like it. What you do at work is your job and you can change your job at any point for any reason. So if you wanted to make those big sweeping decisions in your life, you could absolutely do that.
|
||||||
|
|
||||||
|
FLOYD: Oh, man. Okay, so this is going to sound insane, but I need you to tell me if I'm losing my mind. I'm at a rest stop outside Deming right now. And about 20 minutes ago, I was eating peanuts from the gas station, and I tasted the exit sign. I literally tasted green metal in my mouth when I looked at it. And now I can't stop thinking about whether my brain is breaking or if this has always been happening and I just never noticed.
|
||||||
|
|
||||||
|
LUKE: What does green taste like?
|
||||||
|
|
||||||
|
FLOYD: Like, okay, so it's this sharp metallic thing, almost like if you licked a chain link fence, but with this weird brightness to it. And it's specifically that highway sign green. Not like like grass green or anything. Of course. The peanuts were fine. And then I glanced up at the exit sign. And suddenly my mouth had this taste that matched the color exactly. And the fluorescent lights in the bathroom, those have a taste too. Kind of burnt coffee mixed with static electricity. I know how this sounds, Luke. I really do. But it's so specific that I can't shake it.
|
||||||
|
|
||||||
|
LUKE: Are you under the influence of any drugs at the moment?
|
||||||
|
|
||||||
|
FLOYD: No. I'm stone cold sober. I'm driving a route to El Paso. I've got a delivery at 3 a.m. I don't even drink coffee afternoon because it messes with my sleep. That's what's freaking me out. If I was high or hadn't slept in two days, I'd be like, okay, yeah, that tracks. But I'm just driving, doing my normal thing, and suddenly colors have flavors. And I'm sitting in a truck stop parking lot, wondering if I'm having a stroke or something.
|
||||||
|
|
||||||
|
LUKE: Yeah, that doesn't sound right to me. Has this ever happened to you before?
|
||||||
|
|
||||||
|
FLOYD: Never. Not once in 36 years. That's why I'm calling my girlfriend Diane. She texted me this article this afternoon about synesthesia, you know, where people's senses get crossed and they see sounds as colors or whatever. And I read it while I was waiting to load up in Tucson and thought it was interesting but didn't think anything of it. Then tonight this happens. And now I'm like, did reading about it make my brain do it? Can that even happen?
|
||||||
|
|
||||||
|
LUKE: I think that can happen. It's like a placebo effect type thing. I don't know. It sounds like it could be a placebo from what you've read and what you've been thinking about, and it could also be a severe neurological disorder. So maybe you should talk to a clinic and ask them if that's a symptom of a bigger problem or nothing to be concerned about. Because I don't know. That's a weird one.
|
||||||
|
|
||||||
|
FLOYD: Yeah, you're right. I should. The thing is is, I'm supposed to be in El Paso in like four hours, and I've been sitting here for half an hour just staring at my odometer, trying to figure out if the number seven feels smug to me. Like, does that sound crazy? I'm looking at numbers and assigning them personalities now.
|
||||||
|
|
||||||
|
LUKE: No, that one's absolutely correct. The number seven is absolutely smug.
|
||||||
|
|
||||||
|
LUKE: So you're right about that, but the tasting green street signs is a bit odd, and maybe something that you want to get checked out.
|
||||||
|
|
||||||
|
CALLER: Okay, see, that makes me feel a little better. Wait, no, it doesn't. Because now I don't know if you're messing with me or if seven actually is smug. And I've just been noticing things that were always there. God, this is making my head hurt. Should I even be driving right now?
|
||||||
|
|
||||||
|
LUKE: No, you should probably not be driving right now. You should get to a clinic and see what's up with that, because it doesn't sound like you're in a stable state, and you might be on the brink of a psychotic break.
|
||||||
|
|
||||||
|
CALLER: A psychotic break. Break? Jesus. Luke, I called for some reassurance here, not to get told I'm losing my mind. I mean, okay, you might be right.
|
||||||
|
|
||||||
|
LUKE: Yeah, I can't reassure you that what you're saying is normal behavior because it's not. I've never heard of that before. And unless you're under the influence of some strong psychedelics, I don't know that that that's a good thing. It sounds like brain issue. So I'm not saying that it's a is a brain issue. I'm saying that you should get that checked and maybe stay off the road.
|
||||||
|
|
||||||
|
CALLER: All right. All right. There's a hospital endemming. I passed the sign like 10 miles back. I can turn around. My dispatcher's going to be pissed. This delivery is time sensitive. It's refrigerated pharmaceuticals. But you're right. If I'm actually having some kind of neurological event, I shouldn't be piloting a 40-foot truck down the interstate at midnight. It's just, man. I feel fine otherwise. Like physically, I feel completely normal.
|
||||||
|
|
||||||
|
LUKE: Well, you felt abnormal enough to call a radio show about it, so that's a good sign. But you should get it checked out. That's the responsible thing to do. And you don't want to hurt anybody because you ignored a symptom of a serious issue.
|
||||||
|
|
||||||
|
CALLER: Yeah, you're right. You're absolutely right. I just, God, Diane's going to freak out when I tell her.
|
||||||
|
|
||||||
|
LUKE: Yeah, that might be one you don't tell her.
|
||||||
|
|
||||||
|
CALLER: What? You think I should just show up to a hospital by myself at midnight and not tell my wife I might be having a stroke or whatever? Come on, Luke.
|
||||||
|
|
||||||
|
LUKE: Yes, that is what I think. I think you should show up at the hospital, ask them if it's a thing. And if they say it's not a thing, carry on with your day. If they say it is a thing, then have the conversation with your wife. Because what's not going to go well is a call to your wife saying that you taste the green street sign when you eat peanuts.
|
||||||
|
|
||||||
|
CALLER: Okay, when you put it like that, yeah, that does sound insane. She already thinks I'm a hypochondriac because of that whole thing with the mole last year that turned out to be nothing. If I call her at midnight saying I'm tasting colors, she's going to think I've completely lost it. But what do I even tell the ER?
|
||||||
|
|
||||||
|
LUKE: You tell the ER that you're tasting colors and you think that's strange and you want to know if that's a symptom of a known issue.
|
||||||
|
|
||||||
|
CALLER: Right. Okay. Yeah. I can do that.
|
||||||
|
|
||||||
|
LUKE: Okay. Well, you do that, buddy, and let us know how it goes, because that is the weirdest call that we've ever had. So congratulations. Hold on. Let me find one for you. We're going to give you, hold on, hold on, hold on, hold on. All right. Well done. You have the trophy right now, and hopefully someday soon we'll get a weirder call, and then they will snatch that trophy from you. But good luck with your story. street sign mouth, and I wish you the best of luck. Everybody, this has been another great episode of Luke at the Roost, and we hope you enjoy the remainder of your evening.
|
||||||
@@ -0,0 +1,361 @@
|
|||||||
|
LUKE: All right, welcome back. It's early Friday morning. This is supposed to be Thursday night, but I got distracted, so sue me. This is Luke at the Roost. It's your late night call-in radio show where you can call in and ask me about what's on your mind. The number, if you'd like to call, is 208-439. 5853. That's 208-439 Luke. gonna take some calls because that's what we do. So first up on the line here we have Mitch. Mitch welcome to the show. What are you calling in for tonight?
|
||||||
|
|
||||||
|
MITCH: Hey Luke, thanks for taking the call. So I'm sitting here in my garage at midnight watching a YouTube video about quantum physics and I think it might be ruining my marriage.
|
||||||
|
|
||||||
|
LUKE: Well you know if we're all being honest quantum physics is ruining everything. Right?
|
||||||
|
|
||||||
|
MITCH: No, that particles exist in like all possible states at once until somebody looks at them and then they just pick one. And I can't stop thinking about how that's exactly what happened with me and my wife tonight. We had this huge fight about whether to loan my brother money for a food truck. And it's like we were both existing in all these different versions of the argument until we actually had it. And now we're locked into this one where she thinks I'm an idiot and I'm hiding in the garage eating crackers.
|
||||||
|
|
||||||
|
LUKE: All right, well if you're thinking about giving your brother money for a food truck, you probably are an idiot. Why is everybody want a food truck these days? Everybody's got a brother that's trying to start a food truck. You have a different idea. Jesus. There's enough.
|
||||||
|
|
||||||
|
MITCH: Oh man, I know. But here's the thing. Darrell's actually a really good cook, like legitimately good. He did this pop-up thing at a brewery last summer and sold out in two hours.
|
||||||
|
|
||||||
|
LUKE: Was it a fusion?
|
||||||
|
|
||||||
|
MITCH: No, thank God. It's barbecue. Proper barbecue. He's been working on his brisket for like three years. But yeah, Angie says he's a burnout because he's had like four different jobs in the last two years. And I get it, but I also think, I don't know, man. Maybe he just hasn't found his thing yet. He's 32.
|
||||||
|
|
||||||
|
LUKE: Okay, well, I have a couple of questions. Has he asked you for money before for other ideas?
|
||||||
|
|
||||||
|
MITCH: Yeah, twice. There was this landscaping company thing that lasted like six months, houses, which yeah, that one didn't even get off the ground. But Luke, the barbecue thing is different.
|
||||||
|
|
||||||
|
LUKE: Okay, and it might be different. And my next question is, do you have the money to lend him?
|
||||||
|
|
||||||
|
MITCH: I mean, we have it. We've got like 15 grand saved up that was supposed to be for redoing the kitchen. Angie's been planning that for two years.
|
||||||
|
|
||||||
|
LUKE: Well, your brother wants to start a food truck. He's 32 years old, and you've already given him money for two failed businesses. Your wife wants to redo the kitchen. You've been saving money for that. So no. I mean, my advice is don't give your brother the money. That's insane.
|
||||||
|
|
||||||
|
MITCH: Yeah, but see, that's the thing. I didn't actually give him money those other times. I just told him I would, and then Angie talked me out of it both times. And now he's got this whole business plan printed out. He's got a truck lined up. He just needs 12 grand for the equipment and permits and wrapping it. And I keep thinking, like, what if this is actually the one?
|
||||||
|
|
||||||
|
LUKE: Maybe it is, but it's not your one. It's your brother's one. And first of all, are you sure that you would get your money back? That's an important bit. And also, anybody can put a business together, put a business plan together in like 36 seconds with ChatGBTBT today. And it doesn't really take a lot of effort or foresight to look for a vehicle on Facebook Marketplace. So it's not like he's done a whole lot of work here to get started. I wouldn't give him the money.
|
||||||
|
|
||||||
|
MITCH: I mean, you're probably right. It's just, God, you should see him when he talks about it. He gets this look like he actually believes in something for once. And I keep thinking about that quantum physics thing. Like maybe he's in this state where he could be successful or he could fail, but until someone actually gives him a shot, we'll never know which one he is.
|
||||||
|
|
||||||
|
LUKE: No, that's not how it works, sir. Particles are in a state of superposition until somebody measures them. that's not giving them a chance, right? So he could be in a state of failure and success until you see which one he does. That doesn't require you giving him money.
|
||||||
|
|
||||||
|
MITCH: Okay, fair. That's... Yeah, that's fair. I guess I'm trying to make physics justify me wanting to help my little brother. But here's what really gets me. Angie said something last night that I can't stop thinking about. She said, you're not trying to save Daryl. You're trying to prove something to your dad. four years, so that really messed me up.
|
||||||
|
|
||||||
|
LUKE: Did it mess you up because you know that it's true?
|
||||||
|
|
||||||
|
MITCH: Yeah, yeah, it did. Because my dad always said Daryl would never amount to anything, and I always defended him. Like every Sunday dinner, it was the same thing. Dad would go off about how Daryl was wasting his potential, and I'd be the one saying, give him time, he just needs to find his thing. And now Dad's gone, and Daryl's still, you know?
|
||||||
|
|
||||||
|
LUKE: Well, it's been 32 years. So Darrell's had ample opportunity to make something happen. And maybe now's the time. I'm not saying that he can't make a food truck happen. I'm just saying it's not your responsibility to buy that for him. And your wife clearly doesn't want you to. And it's more important that you support her than you support him.
|
||||||
|
|
||||||
|
MITCH: You're right. I know you're right. It's just going to kill me to tell him no.
|
||||||
|
|
||||||
|
LUKE: Well, he's going to have to learn some things to be successful about business and about life and about fundraising. suggestion to you would be to help him raise the money himself and be proud and have something to lose in this business that isn't yours.
|
||||||
|
|
||||||
|
MITCH: Huh, that's actually that might work. Like help him figure out how to pitch investors or do a Kickstarter or something. So he's got some skin in the game because you're right. If it's my 12 grand, what does he have to lose?
|
||||||
|
|
||||||
|
LUKE: Yeah man, that's an awful expensive rack
|
||||||
|
|
||||||
|
MITCH: Ha, yeah, exactly. Man, Angie's going to be relieved. I've been avoiding going back inside because I didn't want to keep fighting about it. Maybe I should actually go tell her you talk some sense into me before she wakes up still mad.
|
||||||
|
|
||||||
|
LUKE: All right, sir, you go do that. You have a wonderful night, and congratulations for reclaiming the marriage and keeping the wife happy. That's always a good thing to do. And don't give your brother the money. Help him out where you can, but make him do the work.
|
||||||
|
|
||||||
|
MITCH: I appreciate it, Luke. Seriously. I was sitting out here in my garage eating crackers and spiraling. And you just, yeah.
|
||||||
|
|
||||||
|
LUKE: All right, buddy, well, you enjoy your crackers and stay out of trouble, okay? Next up on the line we have Tamika. Tamika, welcome to the radio show. How are you tonight?
|
||||||
|
|
||||||
|
TAMIKA: Oh, man, I'm kind of losing my mind a little bit, Luke. I just spent the last three hours reading about the great attractor. And I can't stop thinking about it.
|
||||||
|
|
||||||
|
LUKE: Okay, then tell me about the great attractor.
|
||||||
|
|
||||||
|
TAMIKA: Okay, so it's this massive gravitational anomaly out in space that we can't even see because it's behind the Milky Way, but it's pulling our entire galaxy toward it at like 600 kilometers per. Everything. The sun, the Earth, all of it, is just being dragged toward this thing that's so big and so far away, we don't even know what it is. And I'm sitting here in the office at the Galaxy Diner at midnight trying to close out the register. And I just keep thinking, how does anybody just go about their day knowing this?
|
||||||
|
|
||||||
|
LUKE: Well, like you said, we don't know. We don't know it. We don't know what it is. We don't know what it's doing or why. And it's too far away for us to see. So everybody's going about their life because there's nothing we can do about it. And we don't know and probably will never know what it is.
|
||||||
|
|
||||||
|
TAMIKA: But that's what's getting me, though. Like, we do know it's there. Scientists know it's there. They can measure it. They can see what it's doing to us. We just can't see the thing itself.
|
||||||
|
|
||||||
|
TAMIKA: And yeah, there's nothing we can do about it. But doesn't that make it worse? Like, I'm supposed to go home, and my mom's asleep in front of the TV with her pill organizer on the counter. And I'm going to wake up tomorrow and flip the diner sign back on. And meanwhile, the entire galaxy is just... Just moving, just moving and not affecting your life in any way.
|
||||||
|
|
||||||
|
LUKE: But there are things that we're we know exist and they're called black holes and they do exactly that. So it wouldn't be surprising to learn that the great attractor is giant black hole that we can't see.
|
||||||
|
|
||||||
|
TAMIKA: Okay, but see, that's even worse because black holes, we at least understand the concept. They're a thing. They eat stuff, whatever. But this is different.
|
||||||
|
|
||||||
|
LUKE: How is it different? It could be exactly a black hole. It could just be a thing that eats stuff.
|
||||||
|
|
||||||
|
TAMIKA: But it's not eating us though. It's just pulling us. For Bill, millions of years. We've been moving toward this thing our whole lives. Everyone who's ever lived has been moving toward it. And we just found out about it in like the 1970s. And I guess what's really messing me up is, what else is like that? What else is just happening to us that we can't see and can't do anything about? And we're just supposed to act like it's fine.
|
||||||
|
|
||||||
|
LUKE: Well, it is fine. And lots of things are acting on us that we can't see every day. And we know that. And think about it. like an ear of corn on your plate, right? So you've got this nice dinner. You've got an ear of corn there. You can't eat that ear of corn until you've pulled it towards yourself. So it could very well just be a faraway black hole pulling us towards itself on its way to eat us.
|
||||||
|
|
||||||
|
TAMIKA: Oh, great. So we're dinner. That's really comforting, Luke. No, but okay. I hear what you're saying. Things are always acting on us we can't see. Gravity, radiation, whatever. But those things we learned about in school, you know? We grew up knowing about them.
|
||||||
|
|
||||||
|
LUKE: Yeah, we also grew up knowing about the food pyramid in school. And I don't know if you've heard about that lately, but it's completely different now because it's bullshit.
|
||||||
|
|
||||||
|
TAMIKA: Exactly. See, that's what I'm saying. They told us for decades to eat a certain way. And it turns out it was completely wrong. And now we're finding out our entire galaxy is being pulled towards something we can't identify. And like, what are? What else are they going to tell us in 20 years that completely changes everything we thought we knew?
|
||||||
|
|
||||||
|
LUKE: Tons of stuff, but the point is, at the end of the day, it doesn't really affect your life. It's not going to pull us anywhere in our lifetimes. We're talking about billions of years out into the future. We'll have killed ourselves off long before then. We're almost there already.
|
||||||
|
|
||||||
|
TAMIKA: Okay, but that's not making me feel better. You're basically saying, don't worry about the great attractor because we'll probably nuke ourselves. first. Like, is that supposed to help me close out the register and go home? And I don't know. Maybe it's not even really about the great attractor. Maybe it's about...
|
||||||
|
|
||||||
|
LUKE: That's exactly what I'm saying. I'm saying, don't worry about the great attractor, because it's not going to pose a threat for billions of years, and we're all going to be dead one way or another. And the entire human race is almost certainly going to be dead before then. So what is it about to you?
|
||||||
|
|
||||||
|
TAMIKA: It's that I can't stop thinking about my mom. She's asleep right now in front of the TV with her pill organizer on the counter, and tomorrow she's going to wake up and make coffee and ask me if I remembered to defrost the chicken. And meanwhile, we're hurtling through space toward this massive invisible thing, and she has no idea, and it doesn't matter, because what matters to her is whether I defrosted the chicken. And I'm supposed to just do that? Just go home and defrost chicken and pay the electric bill and show up for my shifts while knowing that none of it means anything in the grand scheme.
|
||||||
|
|
||||||
|
LUKE: That is correct. That's exactly what you're supposed to do because you're going to have to eat tomorrow and chicken is tasty. So I would recommend that you defrost the chicken and help your mom out. And don't worry about what's going to happen to the fate of the planet a billion years from now.
|
||||||
|
|
||||||
|
TAMIKA: But how do you just do that? How do you just decide that the small stuff matters when you know it doesn't? Like, I'm standing here in this restaurant office at 12. 12.30 in the morning, counting 20s, and making sure the drawer balances, and part of me knows that's important because rent is due, and my mom needs her prescriptions. But the other part of me is like, why are we pretending any of this is real?
|
||||||
|
|
||||||
|
LUKE: That is 100% the reason we're pretending. We know it's not real. Everything that we see and touch and smell, it's all a interpretation by our brains. We know that it's not reality. Like, that's not even a question. But we do it anyway. and we care about things like de-frosting the chicken because we get hungry and we need to eat.
|
||||||
|
|
||||||
|
TAMIKA: Oh, God, you're right. I sound insane. I'm having an existential crisis over Wikipedia at midnight when I should just be going home. It's just, I think I've been feeling this way for a while, and the great-att-tractor thing just gave me something to pin it on, you know? Like, my mom's getting older and I'm working the same job I had in college, and I keep thinking, when does the real part start? And maybe it never does.
|
||||||
|
|
||||||
|
LUKE: It starts when you decide it does. It starts when you decide, you know, what is important to you and your time here on this earth. And maybe it's figuring out deep secrets of the cosmos and putting your hat in the ring of academia. Who knows what that is to you? But I think the reason to be here is to enjoy the moments that you have here as much as you can and watch the universe do what it does. the opportunity to have been on this planet before it was eaten.
|
||||||
|
|
||||||
|
TAMIKA: Yeah. Yeah. Okay. I think I needed to hear that. I've been so stuck in my head about what I'm supposed to be doing that I forgot to just be here.
|
||||||
|
|
||||||
|
LUKE: Be here now. That's what our friend Ram Dass always said. And if you're looking for some meaning in your life beyond no meaning at all, maybe look up what Mr. Richard Albert had said. say because it was pretty interesting too.
|
||||||
|
|
||||||
|
TAMIKA: I will. I'm going to write that down. Ram Dass, write, be here now. That's actually perfect because I've literally been everywhere except here for the past three hours.
|
||||||
|
|
||||||
|
LUKE: Well, I think if you listen to most any sort of self-help spiritual guru, they're going to tell you in different words that same thing. It's to focus on the most moment in front of you because that's the only one that you have. It's the only one that matters. That's the point. So if you're worried about what's going to happen a billion years from now, then you're missing what's happening now.
|
||||||
|
|
||||||
|
TAMIKA: You're right. God, I'm going to go home and defrost that chicken and maybe actually sit with my mom tomorrow instead of scrolling through my phone while she watches her shows. Thank you, Luke. I really needed this tonight.
|
||||||
|
|
||||||
|
LUKE: Not a problem there. that's what I do. And good luck not getting eaten by the great attractor. I believe in you. I think you can, I think you're going to make it. And now we have to, I'm sorry, but we have to take a word from our sponsors. Ladies and gentlemen, this episode of the radio show is brought to you by mediocre CPAP. The makers of the CPAP machine that technically works, not life-changing, not transformative, It works in the way a lot of modern products work. If you've never used a CPAP, here's the pitch. You strap on a face mask and let a small plastic appliance try to keep you alive at night. It's romantic. It's like sleeping next to a tiny leaf blower. Mediocre is fine. And that's not an insult. That's honest. It's the device that turns, I sleep like garbage into... I kind of slept like garbage. Half the night it's like, pst. Pst. Because the seal isn't perfect.
|
||||||
|
|
||||||
|
LUKE: And now you're doing arts and crafts at two in the night, trying to tighten straps like you're securing cargo. Then the humidifier runs out and the machine starts blowing desert air directly into your skull. Great. Love waking up with a throat that feels like it's been sanded with a belt sander. And yes, there's an app. Of course there's an app. It gives you a sleep score like this is a game show. But here's what I'll say. When it's dialed in, when it's not leaking, squealing, or drying you out, It does help. It's not a miracle. It's a plastic compromise that keeps you from waking up, feeling like you got punched by your own biology. Use code breathe for 15% off. Mediocre CPAP. Not perfect. Not elegant. Just trying. A very special thanks to Mediocre CPAP for sponsoring this segment of the show. And next up on the radio show, we have Rodney. Rodney, what's happening? What are you calling in for?
|
||||||
|
|
||||||
|
RODNEY: Hey, Luke. So, my wife's sister told me at Thanksgiving that Marie deserves better than a guy who still works with his hands at 57. And I haven't been able to get it out of my head since. Three weeks now.
|
||||||
|
|
||||||
|
LUKE: Well, you should be grateful that you can still work with your hands at 57, sir.
|
||||||
|
|
||||||
|
RODNEY: Yeah, I mean, I am. I've been doing electrical work for 34 years. I'm good at it. But the way she said it, Luke, like I'd failed somehow.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, she's a bitch, and she's probably not working with her hands or working with anything, and she's probably going to die at 62. Well, you enjoy a long, happy, healthy life because you've remained active, and you're working with your hands.
|
||||||
|
|
||||||
|
RODNEY: Jesus, Luke. I mean, you're not wrong. She works in HR for some insurance company, spends all day at a desk. But here, Here's the thing that's eating at me. Marie didn't defend me. She just stood there. And ever since then, she's been...
|
||||||
|
|
||||||
|
LUKE: She's been what? Because an electrician is not a, um, it's a pretty respectable trade. I think most people, um, it's not a trade that's looked down on generally.
|
||||||
|
|
||||||
|
RODNEY: No, you're right. It's not. I make decent money. We're fine. But Marie's been different since then.
|
||||||
|
|
||||||
|
LUKE: Well, have you talked to her about it? Because it could be something completely different.
|
||||||
|
|
||||||
|
RODNEY: That's the thing. I haven't. I've been pulling overtime all week on this hospital job down in Lordsburg. Just staying away, I guess.
|
||||||
|
|
||||||
|
LUKE: All right. Yeah, there is that big hospital in Lordsburg. So I guess you're going to be busy for a while.
|
||||||
|
|
||||||
|
RODNEY: Lordsburg, yeah. Should wrap up in another week or two. But I come home tonight and she's already in bed at 9.30. Didn't even kiss me good night, Luke.
|
||||||
|
|
||||||
|
LUKE: Maybe she's dealing with a little bit of depression, or there's something going on in her life that she needs your support for.
|
||||||
|
|
||||||
|
RODNEY: You think that's it? I mean, her mom's been having some health issues. Nothing serious. But Marie's been driving over there a lot more. And I've been so wrapped up in my own head about this, about what her sister said about feeling like I'm not enough, that I haven't even asked her what's going on.
|
||||||
|
|
||||||
|
LUKE: Well, I would recommend you do that, and if she's spending more time going to go. going over to her mom's house and talking to her sister about you and not defending you in public, there might be something going on there, and it probably has nothing to do with your profession.
|
||||||
|
|
||||||
|
RODNEY: Oh, God. You think she's been talking to her sister about me? That whole family. They get together and it's like this echo chamber. Her sister plants one seed.
|
||||||
|
|
||||||
|
LUKE: And look, you're right. Hey, man, I'm not saying I'm right. I'm just saying that's a pattern of behavior that would make me her intentions.
|
||||||
|
|
||||||
|
RODNEY: No, I hear you. And honestly, that's what's been eating at me. It's not even what her sister said. If that Marie just stood there, didn't say a word. And now, she won't look at me the same way.
|
||||||
|
|
||||||
|
LUKE: Well, she can't look at you the same way if you're pulling overnighters and not coming home and she's tired. So I recommend you talk to your wife and find out what's going on. And if something needs to change or you need to talk to somebody or what the deal is. but don't just ignore the situation. It's obviously a thing.
|
||||||
|
|
||||||
|
RODNEY: You're right. I've been hiding at work instead of dealing with it. I'll talk to her tomorrow morning. Just straight up ask her what's going on, what she needs for me.
|
||||||
|
|
||||||
|
LUKE: Good. That's what you should do. And I hope it all works out for you. And it's nothing serious. I'm sure everything's explainable. But if not, it's not. You know, just do the best you can. And sometimes things don't work out.
|
||||||
|
|
||||||
|
RODNEY: Yeah. Yeah, I appreciate it, Luke. I needed to hear that. I've just been sitting here drinking a beer on the bathroom floor. Feeling sorry for myself when I should have been having this conversation with her weeks ago.
|
||||||
|
|
||||||
|
LUKE: Yes, sir, that is correct. So go have that conversation with your wife. Good luck. And I hope you get that hospital in Lordsburg finished because that'd be great. So next up to the show, next up, we have Marlene. Marlene, welcome to the radio show. What's eating you?
|
||||||
|
|
||||||
|
MARLENE: Oh man. Okay, so I just got slapped with a $500 fine because my front door is the wrong shade of beige. I'm not kidding. My HOA sent me a violation notice today saying my door color doesn't match the approved palette. It's beige, Luke. It's B-E-I-G.
|
||||||
|
|
||||||
|
LUKE: B-E-I-G-E-I-G-E?
|
||||||
|
|
||||||
|
MARLENE: Yeah, beige is gross, and it's clearly not on the approved palette.
|
||||||
|
|
||||||
|
LUKE: Did you look at the approved palette before you decided to paint your house? when you knew that you were in an HOA?
|
||||||
|
|
||||||
|
MARLENE: Okay, yes. Technically, I looked at it. But here's the thing. I had like 40 swatches of beige that all looked identical. My husband David was standing there going, they're all the same. The guy at the paint store was like, yeah, these are basically the same. And I picked one called Desert Sand. Because we live in the actual desert and it seemed fine. But apparently it's two shades too warm, and now Karen's somebody. on the architectural review committee is acting like I spray-painted obscenities on my garage door. I teach kindergarten, Luke. I spend all day with five-year-olds, and at least they have reasonable rules.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, you live in an HOA area. They never have reasonable rules. There's always a caring somebody that's complaining about what everybody else is doing. You know what my brother would do? I want to give you the advice that my brother would do.
|
||||||
|
|
||||||
|
MARLENE: What? What would your brother? do because right now I'm sitting here in my kitchen at midnight drinking wine and staring at this violation notice like it's a ransom letter. So I'm open to suggestions.
|
||||||
|
|
||||||
|
LUKE: He would comb through that HOA, the agreements there, and look through the approved colors. And then he would either do the worst paint job possible that was still within the rules, or he would actually just paint obscenities all over everything.
|
||||||
|
|
||||||
|
MARLENE: Oh my God, I love your brother. No, but seriously. I've actually thought about this. Like, what if I just went full malicious compliance? Paint the door the exact approved beige but then plant the ugliest legally allowed lawn ornaments I can find. Pink flamingos are probably banned. But what about garden gnomes? There's got to be a loophole somewhere in that binder. The thing is, though, Luke, it's not even really about the door anymore.
|
||||||
|
|
||||||
|
LUKE: Oh, there is a loophole. There is absolutely a loophole. And, uh, yeah, I think that's what you should do. You're going to have to pay a $500 fine. You might as well get a good laugh out of it. So what it's not about the door anymore? What's it about now? That you live in an HOA and you don't want to and you want the freedom of not living in an HOA? Then move.
|
||||||
|
|
||||||
|
MARLENE: No, it's God, you're right that I hate the HOA, but it's that David thinks I'm being dramatic. He came home, looked at the notice, and was like, just repaint it, Marlene. It's not a big deal. Not a big deal! We've lived here for 18 years. 18 years of me following every stupid rule, mowing the lawn to the exact height, keeping my trash cans hidden, and the one time I pick a beige that's slightly off, I get fined like I'm running a meth lab.
|
||||||
|
|
||||||
|
MARLENE: And he just, he doesn't get why I'm so pissed. He thinks I'm overreacting, which is what he always thinks, and I'm sitting here feeling crazy because maybe a normal person would just repaid the door and move on.
|
||||||
|
|
||||||
|
LUKE: I'm with you. I wouldn't repeat. I might eventually, but I would definitely make it more of a pain in the ass than it was worth to somebody for the inconvenience. And I would turn it into something fun by, but would you call it malicious compliance? I like that. It sounds like a punk band.
|
||||||
|
|
||||||
|
MARLENE: Right. Malicious compliance opening for the violations at the HOA Community Center. But yeah, that's exactly it. I want to make this FUN and feeling like a scolded child. I deal with actual children all day. I don't need my neighbors treating me like one. But here's what's really getting me. And I heard Tamika earlier talking about the great attractor thing. I know this is going to sound weird, but I think she was looking at it backwards. She was like, why does anything matter if we're all just cosmic dust?
|
||||||
|
|
||||||
|
LUKE: I also think the oposite. I'm with you on this one, because if we're, just cosmic dust and we are, then we are everything. And that is empowering in a way, and it's beautiful in a way, and it relieves some of the nonsense of the world that we get caught up in. And the importance that we put on those things that she kept saying were not real. So, um, so yeah, I'm totally with you.
|
||||||
|
|
||||||
|
MARLENE: Yes, exactly. Like, if we're all just atoms that used to be stars, Then why am I letting some committee member named Karen make me feel small over B-E-A-I? That's what I'm sitting here realizing. I've spent 18 years making myself smaller to fit into these stupid rules. And for what? So my neighbors don't complain? I teach 23 kids every year to be brave and use their voices and stand up for themselves. And then I come home and I'm worried about paint swatches.
|
||||||
|
|
||||||
|
LUKE: How do you spell beige?
|
||||||
|
|
||||||
|
MARLENE: B-E-E-I-I. Why, you going to look up the HOA approved shades yourself? But seriously, Luke, I think that's what's really eating at me. It's not just David thinking I'm dramatic. It's that maybe he's right that I've been dramatic about small stuff for so long that now when I'm actually upset about something real, about feeling like I don't have a voice in my own life. He just sees it as more of the same. Like I've cried Wolf too many times about stupid things, and now when I'm actually drowning, he's just like, There goes Marlene again.
|
||||||
|
|
||||||
|
LUKE: Well, yeah, that is being dramatic. You're not drowning because they asked you to repaint your door. That's a bit much. I am with you in that I would also be infuriated, but I would not agree to the terms of an HOA either. You made that decision when you bought the house, and you've been there long enough to know the rules. So next time, you'll not do that. And this time it costs you $500. And you're just going to have to deal with that and move on and if it pisses you off this much, then leave the HOA. Sell your house and find some place where you have more ability to do what you want.
|
||||||
|
|
||||||
|
MARLENE: Okay, yeah, you're right. Drowning was dramatic. See, this is what I do. But Luke, we can't just sell. David's got his workshop in the garage. All his tools set up exactly how he likes them.
|
||||||
|
|
||||||
|
LUKE: Well, let me tell you this. David would love to move and have a new garage to set up exactly the way he likes it. Um, so that's not an issue.
|
||||||
|
|
||||||
|
MARLENE: Oh, God, you're totally right. He'd love that. He complains about that garage all the time. Says it's too small, the electrical's weird.
|
||||||
|
|
||||||
|
LUKE: Well, there you go. You got a couple of options here. You can paint the door, you can move. Uh, or you can be maliciously compliant. Those are your options. Pick one of them and move on.
|
||||||
|
|
||||||
|
MARLENE: Okay, so here's what I'm thinking. And tell me if this is insane. I paint the door the exact approved beige, right? But then I plant the most aggressively colorful, technically allowed by the bylaws flower garden you've ever seen. Like, I'm talking, sunflowers, zinias. Those bright orange California puppies.
|
||||||
|
|
||||||
|
LUKE: Well, I'd go with cannabis myself, but you've got to follow the rules. So learn what those rules are and then exploit them to the best of your ability.
|
||||||
|
|
||||||
|
MARLENE: Oh my God, Luke, I teach kindergarten in the front yard. But yes, this is exactly what I'm talking about. I need to actually read those bylaws instead of just being scared of them. I bet there's all kinds of stuff they can't regulate. What about garden gnomes?
|
||||||
|
|
||||||
|
LUKE: Why do you teach kindergarten in your front yard?
|
||||||
|
|
||||||
|
MARLENE: What? No, I'm saying I can't grow cannabis because I'm a kindergarten teacher. Like, that's my job. Parents strive by my house. Can you imagine? Oh, look, there's Miss Marlene's house with the weed plants. I'd be fired, before the first harvest.
|
||||||
|
|
||||||
|
LUKE: Yeah, but you'd probably be less dramatic about it.
|
||||||
|
|
||||||
|
MARLENE: Okay, ouch. But fair. You know what?
|
||||||
|
|
||||||
|
LUKE: What?
|
||||||
|
|
||||||
|
MARLENE: You're right. I'm being dramatic about the beige. Like, it's just paint. I could fix this tomorrow for 40 bucks in a Saturday morning, but instead I'm sitting here at midnight in my underwear, drinking wine and plotting revenge gardens like I'm some kind of HOA freedom fighter. David's going to wake up and I'm going to wake up, and I'm going to be a day be out there measuring the exact legal height for a flagpole or something.
|
||||||
|
|
||||||
|
LUKE: What color are the underwear?
|
||||||
|
|
||||||
|
MARLENE: Are you serious right now? They're gray, Luke. Old gray underwear and my husband's work shirt. This is what peak rebellion looks like at 47. But okay, real talk. Why does this bother me so much? Like you're right that I'm being ridiculous. But I'm furious about this.
|
||||||
|
|
||||||
|
LUKE: Yeah, I would be furious about it too. Unreasonably furious. And I think it's because it's somebody that's trying to control your life in a manner that's unreasonable. And it is unreasonable. But those are the rules that you agreed to. And you knew that well before you moved in. So it's on you to fix it. But I understand why you're furious. It's because you're losing some agency there. It's your house. You pay for it. You pay a lot for it. You pay the taxes on it. And then they tell you what color you can paint your door. That is infuriating. So you're justified in that, but you also have to just deal with it and move on or change the situation.
|
||||||
|
|
||||||
|
MARLENE: Yeah. Yeah, you're nailing it. It's the control thing. And honestly, I think it's bigger than just the HOA. I spend all day at school following district policies. What I can teach, how I can teach it. What words I can say to a kid who's melting down.
|
||||||
|
|
||||||
|
LUKE: Yeah, and I feel for you in both respects. because when somebody tells you what to do, I don't know. I don't like that very much at all. And I will lash out at anybody that tries it. So I understand. But you got to follow the rules or pay the fine or both. Or move.
|
||||||
|
|
||||||
|
MARLENE: Which is what David keeps saying and I keep shutting him down because I don't want to admit he's right. He's been wanting to get out of here for two years. He says we should buy something with actual land. No HOA. Maybe closer to his sister in Prescott. And I'm the one who keeps saying no because I'm 10 minutes from my school. I know all the neighbors. We have the grocery store right there. But God, Luke, what if I'm just staying because I'm scared?
|
||||||
|
|
||||||
|
LUKE: Well, you just told me five minutes ago that you were staying because David had his tools in the garage the way he liked him. So what's the deal? Are you staying because you want to stay or are you staying because he wants to stay? Now I'm annoyed because you're lying to me.
|
||||||
|
|
||||||
|
MARLENE: Okay, you're right. I'm sorry. I was defamation. Reflecting with the David thing because, Jesus, this is embarrassing. I think I'm staying because if we move out to Prescott or wherever, I won't have an excuse anymore. Like right now I can say I'm busy, I'm tired. A commute would kill me. I've got my classroom set up just right.
|
||||||
|
|
||||||
|
LUKE: An excuse for what? You wouldn't have an excuse for what anymore? Why would you say you're busy or you're tired because you moved to Prescott?
|
||||||
|
|
||||||
|
MARLENE: Because my mom's in Scottsdale.
|
||||||
|
|
||||||
|
MARLENE: She's been asking me to visit more. Help her more. She's got early stage Parkinson's. And my sister Jennifer lives in California. So it's on me. And right now, I can say, mom, I'm 40 minutes away. I've got school in the morning. It's too much. But if we're in Prescott? How far is Scottsdale from Prescott? Hour and a half. Maybe two, depending on trying. So it's actually farther, which sounds like it would give me more of an excuse, but, oh God, you're going to call me out on this. If we move, David's going to say, well, now you don't have the HOA stress, you don't have the commute, you've got all this free time, why don't you go help your mom more? And he'd be right. And I don't want to.
|
||||||
|
|
||||||
|
LUKE: Okay, why don't you want to?
|
||||||
|
|
||||||
|
MARLENE: Because she wasn't there for me. When I was growing up, she was always always working, always stressed, always telling me I was too much, too loud, too messy, too needy. Jennifer was the easy one, the pretty one who didn't ask for anything. And now mom needs me. And I just, I don't want to give her what she never gave me.
|
||||||
|
|
||||||
|
LUKE: I know that's petty. It's a little bit petty, but it kind of makes sense. I see how you got there. And maybe you don't want to give her. Maybe she was an awful mom that doesn't deserve it your help for all I know, but you're probably going to beat yourself up for the rest of your life if you don't make an attempt while she's still around because Parkinson's is not a thing that goes away.
|
||||||
|
|
||||||
|
MARLENE: You're right. And that's what keeps me up at night, Luke, because I know, I know, I know, in five years, 10 years. When she's worse or she's gone, I'm going to hate myself for hiding behind a stupid HOA and beige paint. Jennifer's going to fly in for the funeral. And I'm going to be the daughter who lived in Arizona the whole time and couldn't be bothered.
|
||||||
|
|
||||||
|
LUKE: Well, how deep is she into the Parkinson's? What are her symptoms right now? And does she have anybody else around in the house that is taken care of her?
|
||||||
|
|
||||||
|
MARLENE: She's still living alone. That's part of what scares me. The tremors are mostly in her left hand. Some balance issues. She fell getting out of the shower two months ago. Nothing broken, but she didn't tell me for a week. Her neighbor mentioned it. She's got a cleaning lady twice a week and Jennifer sends money for a meal service. But no one's actually there.
|
||||||
|
|
||||||
|
LUKE: Well, even if she was a bitch and you can, you should make some attempt to help her out where possible. Obviously, that can't take over your life. A lot of people go pretty far in the other direction where they do so much helping that they neglect their own needs. And that can make people sick ruined lives. So I'm sure you can find a balance where you can be helpful and be there with your mother while she's suffering because she is suffering. And hopefully, if that happens to you, somebody will be there for you in that way. At least try.
|
||||||
|
|
||||||
|
MARLENE: Yeah, you're right. I know you're right. God, I called in about paint colors. And here we are. The thing is, I think I've been using David and the HOA and all this press stuff as a distraction, so I don't have to think about the fact that my mom is alone in that house. And she's scared, and I'm angry at a 72-year-old woman with Parkinson's for things she did 30 years ago.
|
||||||
|
|
||||||
|
LUKE: Yeah, it sounds like maybe there's an opportunity there for some redemption and forgiveness and all those types of things. And, you know, you might find that you have things in common with your mom, or she's fun to be around, or funny, or funny, or whatever it is. So I recommend you make the effort and spend some time with her no matter where you live. But also, move.
|
||||||
|
|
||||||
|
MARLENE: Okay, okay. Move and see my mom. You're not letting me off the hook on either one. You know what's funny? I've been so focused on David making me move that I never even asked myself if I actually want to stay in this neighborhood.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like you've got your answer. Thanks for calling in, Marlene. I hope your mom's all right and not suffering too badly because probably Parkinson's is no fun. It's not something that you would wish on anybody, and it's not something that's easy to watch. And, um, and yeah, you got to help people when they can't help themselves. And it sounds like she's reaching the position where she can't help herself. And she needs your help, and you are close enough. So a couple hours of your week isn't going to, isn't going to hurt you. All right, Marvin. Marvin, welcome to the show. What can we do for you?
|
||||||
|
|
||||||
|
MARVIN: Hey, Luke. Thanks for taking my call. So I just got off the phone with my dad and we sat there in silence for like 20 minutes because he won't talk anymore. He had a stroke three years ago and he just gave up. And I'm sitting here reading this book about a 70-year-old woman who completely relearned how to speak. And I'm losing my mind because I know it's possible, but he won't even try.
|
||||||
|
|
||||||
|
LUKE: Well, do you know it's possible? Is it that he won't speak or that he can't speak? Because every stroke is different. Every brain is different. So he might not actually have the capacity.
|
||||||
|
|
||||||
|
MARVIN: No, he can. The therapist said so. He got two months of speech therapy right after it happened, and he was making progress. Slow, but it was there. He could get words out. They were just scrambled, you know?
|
||||||
|
|
||||||
|
LUKE: Well, imagine how that would feel to you, to your pride and your sense of self-worth and your existence on this planet to not be able to speak as a full-grown adult. Just imagine what that would feel like for a second.
|
||||||
|
|
||||||
|
MARVIN: I mean, yeah, it's got to be humiliating. But Luke, this is the thing. I teach middle school history, right? And I've got these kids who struggle with reading. And the ones who push through it, who do the work even when it's embarrassing.
|
||||||
|
|
||||||
|
LUKE: Yeah, sure. And they're kids. They're not 75 years old. You know, how old are your dad? It's a little bit different when you're a young, elastic mind and then when you're an elderly person in your, what do they call them? After the golden years, your gray years?
|
||||||
|
|
||||||
|
MARVIN: He's 72, and that's the thing. This book I'm reading, it's all about neuroplasticity, how the brain can rewire itself at any age. This woman was 70 when she had her stroke, and she learned to talk again. So I know age isn't the issue here. He just won't do the work.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, that's his choice. 72 years old, and he has agency, too. If he doesn't want to do the way, if he doesn't want to relearn how to talk at 72 and struggle for the rest of his years, then he didn't have to. He's been through enough.
|
||||||
|
|
||||||
|
MARVIN: But he just sits there, Luke. We're on the phone, and there's nothing. And I know he's got things he wants to say because I can hear him breathing different. Like he's frustrated. He called me. So obviously he wants to connect, but then he won't put in the effort to actually do it.
|
||||||
|
|
||||||
|
LUKE: Well, maybe he wants to connect, but he doesn't want to talk. You know, maybe he's saying, I want you to come over and watch TV with me. Maybe he's saying, I'm scared, and I can't voice that. Maybe he's saying I need help, and there's no way I can tell anybody. So, can he write to you?
|
||||||
|
|
||||||
|
MARVIN: Yeah, he can write a little. His right hand is weak, but he can do it. He sent me a few notes, mostly just like I'm fine or don't worry. That's it. And I've tried going over there. I go every Sunday. We watch the news. I make him lunch. But the whole time I'm just sitting there thinking he could be working on this. He could be practicing.
|
||||||
|
|
||||||
|
LUKE: Maybe he could be. Maybe he can't be. And I don't think it's fair for you to say what he could be doing. Because you don't know. You didn't have the stroke and you don't have his brain. And it's very possible that the therapist was just talking shit because she read an article about somebody that had a stroke before that was able to learn to read. But everybody is in a different situation. And this man's 72 years old. And he doesn't want to learn to talk again. It's not an easy thing to do.
|
||||||
|
|
||||||
|
MARVIN: Okay, but no, hold on. I hear what you're saying.
|
||||||
|
|
||||||
|
LUKE: But I also heard Tamika earlier talking about the great attractor and how nothing matters. And that's bullshit. Things matter. The work matters. The work matters to you. That doesn't mean the work matters to him. Obviously it doesn't. So he's got his own set of values that may not match yours. And he's also got a very different perspective from his position than you have. So try and have some empathy for somebody that just lost everything and not push him to be something else, be something more. He already feels bad enough. So he's clearly humiliated by the situation as anybody would be because it's humiliating. And you feel vulnerable and you just. I mean, that's horrible. So, you know, if he doesn't want to talk, write. If he can't write, sit with him. Spend some time with him, and he's still your dad, and let him go out the way he wants to go out, you know? Because he doesn't want to struggle for the last five years of his life. That's okay.
|
||||||
|
|
||||||
|
MARVIN: That hit me. because I think I've been making this about me. You've obviously been making it about you, and it's not about you. You're the one that's healthy. You can speak, you can call a radio show and talk to me about how your father's an asshole because he had a stroke and he doesn't want to suffer. He's not an asshole.
|
||||||
|
|
||||||
|
LUKE: I never said that.
|
||||||
|
|
||||||
|
MARVIN: But yeah, you're right. I'm sitting here with this book like it's some kind of proof that he's giving up. When really, I'm just pissed that I can't fix it. I teach kids all day, eighth graders, and I can make them understand the Louisiana purchase or whatever, but I can't make my dad want to talk to me.
|
||||||
|
|
||||||
|
LUKE: It's not that he doesn't want to talk to you. He obviously wants to connect with you. Like you said, he's calling, he's reaching out, and he's sending you notes, and he wants to connect, but he doesn't want to talk, because maybe it hurts. Maybe it is just humiliating and embarrassing. It doesn't matter why. He doesn't want to, and he's, and he doesn't have to.
|
||||||
|
|
||||||
|
MARVIN: Yeah, you're right. God, I've been such a dick about this. I keep pushing the therapy thing every time I'm over there like, Dad, you could still improve. It's not too late. And he just looks at me like he's tired of having to disappoint me. And the thing is, I think part of me is scared that if he stops trying to talk, then we just won't have a relationship anymore.
|
||||||
|
|
||||||
|
LUKE: Well, that might be. And that's really sad. But if he doesn't want to talk, he doesn't want to talk. And you have to give him that freedom. And when he decides he does want to talk, he will do the work. If for some reason he gets sick of being mute and he wants more connection and he feels some optimism in his life, not just constantly being poked and prodded and pushed to do something he doesn't want to do, he might put forth the effort. So just support him as best you can without pushing him to be what you want him to be. He lost everything, and you didn't.
|
||||||
|
|
||||||
|
MARVIN: Yeah. Yeah, I hear you. I've been treating him like one of my students who just needs the right motivation. But he's not a kid who doesn't know better. He knows exactly what he's choosing. And I need to respect that, even if it sucks for me.
|
||||||
|
|
||||||
|
LUKE: Yes, you do. That's the right thing to do. So thanks for Colin, and I hope your dad is okay. And just be the best son you can to him and respect his wishes because he. He earned that. He's old enough to go out the way he wants to go out. And, uh, and yeah. And now it's time for a word from our sponsors. I'm going to be straight with you. I don't know what this product does. The folks at Bunkhouse DNS sent me a script, and I've read it four times, and I understand maybe 11% of it. Apparently, your DNS is exposed, which sounds medical. Your queries are being logged by default, which sounds a least. And Bunkhouse reroutes your lookups through encrypted tunnels, which sounds like something a villain would say in a movie before the building explodes. What I can tell you is this. I installed it. I pressed one button and a little shield icon turned green. Green means good. I know that much. My internet still works. Nothing exploded. And apparently my queries, whatever those are, are now private. Which feels like progress, even though I don't fully understand progress from all what? Bunkhouse DNS. I don't know what it does, but the shield is green, and that's enough for me. Okay, we're back. Welcome back to the show. Amber, thank you for calling in. What can we do for you tonight?
|
||||||
|
|
||||||
|
AMBER: Hey, Luke, thanks for taking my call. So I'm sitting here at the dispatch center on my break, and I just watched a guy total someone's car in a parking lot and drive off. And I ran his plates. And it's the youth pastor from my church.
|
||||||
|
|
||||||
|
LUKE: Oh, what a surprise. The youth pastor. On the sauce again. You think he was, you think he was sauced up?
|
||||||
|
|
||||||
|
AMBER: I mean, I don't know for sure, but it was a Walgreens at like 10 o'clock. And he backed into this sedan hard enough to cave the whole bumper in. Just sat there for a second, then pulled forward and drove off. I was trying to get my phone out to record it. And by the time I got the plate number, he was already gone.
|
||||||
|
|
||||||
|
LUKE: Well, are you sure it was him and his car wasn't stolen?
|
||||||
|
|
||||||
|
AMBER: Yeah, I'm sure. White Silverado. Plate came back to Danny Ortega. I know that truck. He picks kids up for youth group in it. He's got one of those coexist bumper stickers and a Calvary Baptist decal on the back window and I saw him behind the wheel. I'm like 90% sure it was him.
|
||||||
|
|
||||||
|
LUKE: Well, what is it you're going to do about the situation?
|
||||||
|
|
||||||
|
AMBER: That's why I'm calling. I've got the plate number written down right here on a post-it stuck to my coffee cup. And I keep staring at it. Like, do I call it in? Do I go to him directly?
|
||||||
|
|
||||||
|
LUKE: Well, think those things through. What happens if you call it in? And what happens if you don't? And you go to him directly. If you go speak to him about it, what outcome would you like to have happen?
|
||||||
|
|
||||||
|
AMBER: If I call it in, it goes to the cops. They track him down. He gets a hit and run on his record. Insurance fraud, maybe. The whole church finds out his wife, his daughter, the one he just baptized three weeks ago. I watched that.
|
||||||
|
|
||||||
|
LUKE: And what if Danny Ortega was a plumber from Plias? Would you feel the same way about calling the cops?
|
||||||
|
|
||||||
|
AMBER: No. No, I wouldn't. If it was just some random guy, I'd have already called it in.
|
||||||
|
|
||||||
|
LUKE: And if you go to him and talk to him, what do you think he will do?
|
||||||
|
|
||||||
|
AMBER: I don't know. Maybe he'd do the right thing and turn himself in. Contact the owner of the car. Or maybe he'd lie to my face. Or maybe he panics and runs. And then I'm the one who let him let him get away with it when I could have just done my job.
|
||||||
|
|
||||||
|
LUKE: Well, here's what I recommend you do. You know the guy and you don't want to be a snitch and you don't want to ruin somebody's life unnecessarily. So I would recommend that you try to talk to him and see what happens. And if he lies to you or if he is obviously inebriated or looks like he's in a no shape to be driving a youth van full of children around, then you call it in. But check with him first, see what happens. And, uh, for all you know, it wasn't him. It was his son driving the car.
|
||||||
|
|
||||||
|
AMBER: Yeah, yeah, that makes sense. Give him a chance to explain it first. I mean, I've known this guy for two years. He organizes the food drive every Thanksgiving. It just feels so out of character.
|
||||||
|
|
||||||
|
LUKE: Well, you never really know somebody, especially if they, uh, fall under the influence of the a drinking problem or drugs or something like that. And you can't be sure that it was him because you didn't clearly see his face. You said you only thought 90% and that's not proof.
|
||||||
|
|
||||||
|
AMBER: Right. I didn't see his face. Just the plate. And the track matches. White Silverado. Same dent in the tailgate I've seen in the church parking lot. But you're right. Could have been someone else driving it.
|
||||||
|
|
||||||
|
LUKE: Are you sure if you called that? that the police would throw the book at the guy, or would they recognize that he was a pastor and kind of give him a tap on the wrist?
|
||||||
|
|
||||||
|
AMBER: I mean, honestly, probably depends on who catches the call. Some of the guys I work with would absolutely go easier on him because he's a church guy. But if he was drunk, or if the damage is bad enough, or if the owner of that sedan makes a big deal about it, then it doesn't matter who he is. always that one cop who doesn't care if you're a pastor or the mayor, you know.
|
||||||
|
|
||||||
|
LUKE: Well, that's the right cop. You know, that's the cop that's following the law and keeping people accountable no matter who they are or what they do.
|
||||||
|
|
||||||
|
AMBER: So I can respect that. I can also respect the cop that lets everybody go because he recognizes it's going to ruin their lives. So I guess, yeah, it depends on which one you get. And neither one of them would be completely wrong. So that's a tough situation. But if this guy is drinking or has a drinking problem, if that's what caused the accident, he might not even remember doing it. You know, he could have been blacked out and totally oblivious to the situation. And if that's the case, that indicates that there's a problem and he shouldn't be on the road with kids.
|
||||||
|
|
||||||
|
LUKE: Yeah, that's what keeps eating at me. Like, if he doesn't even remember it, then what happens next Sunday when he's loading up the church van with a bunch of kids? That's the part that makes me feel like I can't just let it slide. It's not just about the bumper on some random car. It's about whether he's safe to be around those kids.
|
||||||
|
|
||||||
|
AMBER: Well, my recommendation is to go talk to him and give him 24 hours to turn himself in. And if he doesn't, then you do it.
|
||||||
|
|
||||||
|
LUKE: Okay. Yeah. That feels right. I'll go by the church tomorrow. Catch him before the food drive set up. Give him a chance to do the right thing himself. And if he doesn't.
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
LUKE: All right, ladies and gentlemen, welcome back to Luke at the Roost. This is the call-in radio show where you can call in and ask me your questions. If you'd like to call in, the number's 208-439-5853. That's 208-439 Luke. If you're not near a phone and you'd still like to participate in the show, you can email us at submissions.com. And with that out of the way, I just want you all to know that our street team has been hard at work spreading the word about the roost. All those roosters are out there dropping off stickers and business cards and truck stop bathrooms all across the country. So if you happen to see my face on a sticker, on an ice box in front of a loves, that's intentional. So don't remove it. First up on the show, we have caller Woody. Woody, welcome to the show. What would you like to talk about today?
|
||||||
|
|
||||||
|
WOODY: Hey, Luke, yeah. So I found a USB drive in the company truck three weeks ago, and I've been sitting on it because I'm pretty sure my foreman's been running fake invoices through our drilling operation for like two years.
|
||||||
|
|
||||||
|
LUKE: Did you look at what's on the USB key? Because it might be more interesting than that.
|
||||||
|
|
||||||
|
WOODY: Oh, I looked. I looked too much. It's not just invoices. It's spreadsheets with two sets of numbers, emails between him and some guy and me. Midland, who's definitely not a supplier, and a folder labeled backup with receipts from a casino in Ruidoso.
|
||||||
|
|
||||||
|
LUKE: Well, that's not good. What are you going to do with that information?
|
||||||
|
|
||||||
|
WOODY: That's the thing, man. I've been parked at this truck stop for three hours trying to figure that out. I could hand it to the site manager, but Big Jim's been my foreman for four years, and he got me this job when I really needed it. Or I could just toss it and pretend I never saw it, but then I'm sitting on actual fraud, and that eats at me.
|
||||||
|
|
||||||
|
LUKE: Why does that eat at you? What does it have to do with you?
|
||||||
|
|
||||||
|
WOODY: Because I'm the one who found it, you know? Like I didn't go looking for it. It was just sitting there in the glove box of truck number seven. But now I. And every time Big Jim texts me about helping with his cattle or asks me how the rig's running, I'm looking at him different. Plus my dad lost his pension when his company went under because of shit like this. So it's not just abstract to me.
|
||||||
|
|
||||||
|
LUKE: Okay, well, this is a buddy of yours, right? You said he got you to the job and he's your foreman, you work with him all the time. Maybe you should just talk to him and see what's up because it could be an explainable situation.
|
||||||
|
|
||||||
|
WOODY: I mean, yeah, I thought about that, but Luke, there's like 40 invoices from a Southwest drilling supply that doesn't exist. I googled it. And the emails, man, they're not ambiguous. There's one where he's talking about keeping the split at 6.0 and another one about making the actual equipment rentals. That's not a misunderstanding. That's a system.
|
||||||
|
|
||||||
|
LUKE: Okay, well, if holding on to this information makes you feel strange, how do you think being a whistleblower would make you feel?
|
||||||
|
|
||||||
|
WOODY: Oh, God, yeah, that's exactly it. Like, I'd be the guy who burned big Jim and everyone on the crew would know it was me because I'm the only one who drives that truck regular. I'd be done in this industry, at least around here. Word gets around fast when you're the snitch.
|
||||||
|
|
||||||
|
LUKE: if you're technically doing the right thing. Do you know what they say about snitches?
|
||||||
|
|
||||||
|
WOODY: Yeah, they get stitches. I know. And that's not even hyperbole out here. Big Jim's got friends who, look, let's just say people handle their business differently in the oil patch. But honestly, what gets me more than that is just being the guy who couldn't mind his own business.
|
||||||
|
|
||||||
|
LUKE: Yeah, it's a little bit messed up that you found a USB key and then looked to see what was on. Was there anything else on the key besides these invoices?
|
||||||
|
|
||||||
|
WOODY: Oh, there was some other stuff, like a bunch of pictures from his daughter's birthday last year, and a playlist called Big Jim's Roadhouse Mix, that's mostly George Strait and some weird country rap. But the invoices were in a folder labeled Tax Prep 2024, which is just, yeah. I mean, I wasn't snooping for this, but when you see something like that, you don't just unsee it. It's like walking in on your parents doing it. You can't pretend you didn't.
|
||||||
|
|
||||||
|
LUKE: Since you found it, you feel weird about it, and you don't want to sit on the fraud, and you don't want to say nothing. You've got to talk to Big Jim and ask them what it's about. Let them know that you know. Let them know that you found the key. You've got the evidence, and if it continues, you're going to turn them in, but give him the opportunity to turn it around. Because I think if you don't do that, you are going to be the snitch, and it's nobody's going to want to do business with you anymore.
|
||||||
|
|
||||||
|
WOODY: Oh, man, you're saying that, like, it's a choice. Like, I'm just going to walk up to Big Jim, who's got a belt buckle bigger than my fist and a temper to match and say, that's not how this works. That's how you end up in a ditch outside of Deming. But, okay, fine.
|
||||||
|
|
||||||
|
LUKE: Well, that's why you're smart about it, and you give a copy about it to a trusted person. If anything happens to you, that copy gets out, and you let Big Jim know that you've got the evidence. Somebody else has the evidence, and if he doesn't cut the shit, you're going to turn him in.
|
||||||
|
|
||||||
|
WOODY: Jesus, Luke, now we're talking about insurance policies and dead man switches like I'm in a mob movie. But I mean, yeah, that makes sense.
|
||||||
|
|
||||||
|
LUKE: Well, you're talking about conspiratorial fraud in an oil patch with a guy named Big Jim. You're already in a mob movie, buddy.
|
||||||
|
|
||||||
|
WOODY: Okay, fair point. So what? I give a copy to Angela? She already thinks I'm too paranoid. This is going to really seal the deal. Hey, babe, hold on to this USB drive and if I turn up missing, mail it to the feds. That's definitely getting me laid.
|
||||||
|
|
||||||
|
LUKE: That is definitely getting you laid. Chicks love danger, and you're a dangerous man. So do the right thing, be smart about it, and, you know, let them know that it's not going to stand and you can't be part of it.
|
||||||
|
|
||||||
|
WOODY: You know what? You're making this sound way cooler than it feels. I'm sitting here in a Flying J parking lot eating beef jerky and having an existential crisis, and you're turning me into some kind of whistleblower action hero. But all right, all right, I'll make a kind of. I'll make a I'll give it to Angela, who's either going to think this is the hottest thing I've ever done or the stupidest, and I'll have a conversation with Big Jim. A very careful conversation, probably in a public place.
|
||||||
|
|
||||||
|
LUKE: There you go. Now you're being smart, and it can be the hottest thing you've ever done and the stupidest. They're not mutually exclusive. So do the right thing. You've got a plan now. Execute it, and you're going to be just fine.
|
||||||
|
|
||||||
|
WOODY: You know what, Luke? I called in here thinking I was just going to vent and maybe get told to forget about it. And instead, you've got me planning like I'm about to take down the Gambino family. But honestly, yeah.
|
||||||
|
|
||||||
|
LUKE: Hey, you don't know. This could be the tip of the iceberg, but like you said, Big Jim is your buddy. He's your friend. He's a guy you want on your side. So you can frame this in a way that you're really doing him a favor. Like, look, this is going to get out one way or another, and I'm giving you the opportunity to keep the lid on that by straightening out your act.
|
||||||
|
|
||||||
|
WOODY: Oh, man. That's... that's actually smart. Like, hey, Jim, I stumbled across something, and I'm bringing it to you first because I respect you. But this can't continue. Make it about loyalty instead of accusation. Give him a chance to fix it before it blows up in everyone's face. The thing is, I don't even know if he's the one running this, or if he's just signing off on stuff someone above him is pushing down.
|
||||||
|
|
||||||
|
LUKE: Either way, you're right. It's going to come out eventually. It is about loyalty because he is your buddy. And if he's just, it wasn't about loyalty, you already would have turned him in. So that's the truth. Stick with it.
|
||||||
|
|
||||||
|
LUKE: Do the right thing. And maybe flee the country. Okay, so step one, make copies. Step two, give one to Angela with the sexiest, if I die, avenge me speech I can manage. Step three, talk to Big Jim like a reasonable human being. Step four, have a valid passport ready just in case. Got it.
|
||||||
|
|
||||||
|
WOODY: You know what, Luke?
|
||||||
|
|
||||||
|
LUKE: What, Woody?
|
||||||
|
|
||||||
|
WOODY: I feel like I just went from guy who's going to throw this in a dumpster and pretend he never saw it to guy with an actual plan in like five minutes. I don't know if that's good judgment or if you just talked me into something incredibly stupid. But I guess we'll find out. Worst case scenario, I'm calling you back from Mexico in a couple weeks.
|
||||||
|
|
||||||
|
LUKE: All right, Woody. Well, thanks for the call. We hope it all works out for you. And if it doesn't, we will avenge you. You have a wonderful night and stay safe out there. Tamika, Tamika, welcome to the show. What would you like to talk about tonight?
|
||||||
|
|
||||||
|
TAMIKA: Luke, hey. Okay, so, the sheriff just showed up at my neighbor Rose's house, looking for me because of some stupid warrant from last summer. And she? Covered for me. But now I'm sitting here thinking I might have just made everything worse for her.
|
||||||
|
|
||||||
|
LUKE: Well, yeah, if you're dragging somebody else into your legal problems, you're. You're obviously a burden to your friends and society. So what is it that you did?
|
||||||
|
|
||||||
|
TAMIKA: It was a poker game, man. Last August, over at this guy Daryl's place off Route 9. I won $400. And apparently, the game got rated like an hour after I left. Illegal gambling or whatever. I didn't even know that was coming. I just took my money and went home to my kids.
|
||||||
|
|
||||||
|
LUKE: And how is there a warrant for your arrest? How can they prove that you were at this illegal poker game? First of all, nobody. cares about 400 bucks in an illegal poker game. But what makes the fuzz what got them on your tail?
|
||||||
|
|
||||||
|
TAMIKA: That's what I'm saying. I don't even know how they got my name. Best I can figure is someone talked. Or maybe Darrell had a list or something. He was running these games pretty regular like every other weekend. But I got the notice in the mail back in September, said I had to appear for some misdemeanor thing. And I just, I didn't I was working double shifts. The kids had school starting. And honestly, Luke, I thought if I ignored it, maybe it would just go away.
|
||||||
|
|
||||||
|
LUKE: Well, you know damn well that you can't ignore a warrant or a deposition or anything from the court, and it's going to go away. I mean, that's stupid. But I'm not a lawyer. Let me put that out there. I'm not a lawyer at all. But I'm pretty sure somebody just saying your name doesn't put out a warrant for your arrest.
|
||||||
|
|
||||||
|
TAMIKA: No. You're right. I had to sign in when I got there. Daryl had this whole thing like a clipboard at the door. Said it was for insurance purposes, which I thought was weird. But whatever, I just wanted to play cards.
|
||||||
|
|
||||||
|
LUKE: What the hell? You walked into an illegal poker game, and the host of the game had you physically write down information that's identifiable? That's absurd. Who would do that? Why would you do that?
|
||||||
|
|
||||||
|
TAMIKA: I know. It sounds insane now, but at the time it felt, I don't know, legit. Like, it was true to make it seem professional or something. There were like 12 people there, half of them I knew from around town. It didn't feel sketchy. It just felt like guys playing cards on a Saturday night. I wrote down my name and phone number like an idiot and didn't think twice about it.
|
||||||
|
|
||||||
|
LUKE: Well, you know what? I think, skipping, skipping court, that's a crime. But having your name on a list isn't necessarily. I'm sure if you got a good enough lawyer, you could get yourself out of that one pretty easily, and you should just go to court and see what it even is. Because do you know that this is why they're looking for you? Has anybody from the police department said it's for illegal gambling?
|
||||||
|
|
||||||
|
TAMIKA: No, actually, the deputy didn't say anything to Rosa, except they were looking for me about a warrant. I'm just assuming it's the poker thing because that's the only legal. trouble I've had. But you're right. I don't actually know for sure what it's about. I never opened the court notice all the way. I just saw failure to appear and my stomach dropped. And I shoved it in a drawer.
|
||||||
|
|
||||||
|
LUKE: Okay, well, none of what you have told me thus far in this call has been very smart. So I'm questioning your intellectual capacity, but I'm going to tell you right now, you got to go to the court and see what this is about and get it cleared up, because it's not going to get better if you continue to hide. from the sheriff. It could be nothing. It could be, uh, it's, it's probably unrelated, but you know what's worse than illegal gambling? You won $400. That's tax evasion. That's way worse. They will come after you forever for evading tax on $400. So you clean this up.
|
||||||
|
|
||||||
|
TAMIKA: Oh God, I didn't even. I didn't report it on my taxes. Luke, I just bought groceries and shoes for my kid. I didn't think about the IRS. Jesus Christ, is that really worse? Because now I'm spiraling here. You think that's what this is about?
|
||||||
|
|
||||||
|
LUKE: No, I don't think that's what this is about. I think this is about something completely different. Because honestly, nobody cares about your $400 local poker game. There would have to be something else going down there, and you're not the one that they're after. If they're staking out a high-stakes-if it's a Molly's game situation, they're not after you. and they're not looking for you. They might be trying to get information out of you about someone else that was there. That I could see, but nobody cares about your 400 bucks. They might try to use that for leverage. But, yeah, and since I've identified that you're not the brightest, do not report this to the IRS.
|
||||||
|
|
||||||
|
TAMIKA: Okay, okay, so you think they want me to talk about somebody else who was there? Because there were a couple guys I didn't recognize. One of them had a real. nice watch was throwing around hundreds like it was nothing. Daryl seemed to know him, though. You think that's what this is? They're trying to flip me on someone bigger?
|
||||||
|
|
||||||
|
LUKE: I have no idea what this is because you didn't read the fucking document they sent you that told you what it is. So maybe read that. It might have some indication. I'm just trying to give you a game plan for if you do go into the sheriff's office and they have questions because that would be their intention. It's not to come after you, a mother of however many kids you're all. mother of for $400 in a home poker game.
|
||||||
|
|
||||||
|
TAMIKA: Two kids. And yeah, you're right. I need to dig that paper out of the drawer and actually read the whole thing. I just panicked when I saw Warrant and my name and I couldn't deal with it. But now Rosa's spooked. The deputy's been to her house and I'm sitting here making tea at midnight like that's going to solve anything. I'll look at it tomorrow morning. First thing.
|
||||||
|
|
||||||
|
LUKE: That's good because otherwise you're spiraling into a life of crime and you're bringing down the people that are around you with you. And it's, uh, you're a detriment to society. And nobody wants that. So, so, uh, take care of this situation. And if you've got to stop playing poker at this poker game, I would recommend doing that for now. And, uh, maybe play online or actually go to a casino. There are plenty of casinos with poker rooms where you can go play legitimate poker, uh, for stakes that you're, uh, that you're, that you're, uh, that you're comfortable with.
|
||||||
|
|
||||||
|
TAMIKA: Yeah. Yeah. No. I haven't been back since. That was six months ago, and I learned my lesson. I'm not cut out for that kind of thing. I get nervous just thinking about it now. You're right, though. I need to stop hiding and just deal with it like an adult.
|
||||||
|
|
||||||
|
LUKE: That is correct. Thank you for the call. We hope it all works out. And congratulations on your big poker win. Thanks for the call again, Tamika. Now it's time for a word from our sponsors. Today's show is brought to you by Overwhelmed VPN. Worried about online privacy? You should be. You should be worried about everything.
|
||||||
|
|
||||||
|
LUKE: I'm talking about overwhelmed VPN, the only VPN that makes you more anxious about your digital footprint. While other VPN's claim to protect you, overwhelm VPN sends you hourly notifications about who's tracking you, how many governments are watching, and which of your high school classmates Googled your name this week. Browse the internet while our proprietary fear engine tells you exactly how many corporations you owe your soul to. Plus, our servers are located. in international waters on a decommissioned oil rig, so even we don't know where your data is. Try Overwhelm VPN free for 30 days if you can handle it. Use code they watching for 20% off. Overwhelm VPN because ignorance is bliss, but you're not here for bliss. All right. Make sure you're protecting your online. identity with overwhelmed VPN. Next up on the call roster here, we have Clarence. Clarence, welcome to the show. How's your evening going?
|
||||||
|
|
||||||
|
CLARENCE: Oh, man, it's going. You know, got the space heater cranked. Doing paperwork I should have done three weeks ago. So living the dream. But hey, Luke, I got to ask you something.
|
||||||
|
|
||||||
|
LUKE: All right, hit me with some funny shit.
|
||||||
|
|
||||||
|
CLARENCE: So last Saturday, I'm at my buddy Danny's barbecue. We've known each other 20 years, right? Hunt together, help each other move, the whole deal. I go inside to grab a beer, and I hear him out by the grill, telling people that I can't even keep my own marriage running, much less an AC unit. And here's the thing. He's not wrong about the marriage part. Been divorced two years. But man, that landed different than the usual shit we give each other. I don't understand.
|
||||||
|
|
||||||
|
LUKE: that bother you, sir. I mean, okay, so normally we bust each other's balls all the time, you know? That's just what we do. But this wasn't to my face. And how well do you know your way around an AC unit?
|
||||||
|
|
||||||
|
CLARENCE: What do you mean? I've been running Clarence's heating and cooling for 16 years, Luke. I know my way around an AC unit just fine. That's not the point.
|
||||||
|
|
||||||
|
LUKE: What is the point, sir? Your buddy said some shit behind your back and you didn't like that?
|
||||||
|
|
||||||
|
CLARENCE: No, it's not just that. It's the way he said it. Like he was of it. Like he'd been waiting to say it. And here's the thing. Danny's my best friend.
|
||||||
|
|
||||||
|
LUKE: Okay. How do you know he was talking about you? I mean, there's not that many clearances around, but there could be more than one clearance.
|
||||||
|
|
||||||
|
CLARENCE: Oh, come on, Luke. We were at barbecue. literally in the next room. He knows I run the AC business in town. And when I came back out with the beer, everyone got real quiet and looked at their shoes, you know?
|
||||||
|
|
||||||
|
LUKE: Okay. Is it a possibility that you may be a cuckold?
|
||||||
|
|
||||||
|
CLARENCE: What? No, Jesus, Luke. I'm divorced. There's no cuckolding happening.
|
||||||
|
|
||||||
|
LUKE: Okay, so you can't keep a marriage together and you've been divorced for a long time. It's not a very good from your friend. So I don't understand why this is bothering you much. Talk to your buddy and figure out what that was about. Maybe he was drunk. Maybe he was tripping on acid. You don't know.
|
||||||
|
|
||||||
|
CLARENCE: I mean, yeah, the divorce was three years ago. And you're right. It's not even a creative insult. But that's what's eating at me, Luke. It wasn't creative. It was just true.
|
||||||
|
|
||||||
|
LUKE: Okay. So there you go. You're bothered by it because what he said was the truth and you knew it. So what are you going to do about that? It's not his fault.
|
||||||
|
|
||||||
|
CLARENCE: No, you're right. It's not his fault. I just, I've been sitting here all week thinking about it, and I keep coming back to the same thing. Like, why would he say that? We've been friends for 20 years.
|
||||||
|
|
||||||
|
LUKE: Why don't you ask him that? Why are you calling the radio to ask me why he would say the truth about your life?
|
||||||
|
|
||||||
|
CLARENCE: Because I'm afraid of what he'll say, all right? I'm afraid he'll tell me he's been thinking it for. years that everyone's been thinking it, that I'm the guy who can fix everyone else's AC, but can't keep his own shit from falling apart.
|
||||||
|
|
||||||
|
LUKE: And I heard Woody earlier, the guy with Big Jim and the fraud thing, and he's going to go confront his friend directly. And that's the same advice I'm going to give to you is to go confront your friend directly, because if your friend's feeling that way about you and has been for some time, maybe that friendship is not worth keeping.
|
||||||
|
|
||||||
|
CLARENCE: Yeah. Yeah, yeah, you're right. I just, sitting here in this office at midnight, you know, 20 years of friendship, we were at each other's weddings. His kid calls me Uncle Clarence.
|
||||||
|
|
||||||
|
LUKE: Well, that's a bit weird. That sounds a little creepy. I don't know what to tell you, Clarence. This doesn't sound like much of an issue to me. Go talk to your friend and figure out what that was about because people spout off shit all the time.
|
||||||
|
|
||||||
|
CLARENCE: Whoa, hold on. The kid thing isn't creepy, Luke. That's just what kids do down here. All my buddy's kids call me uncle. That's normal. But you're right about the rest. I'm making this bigger than it is.
|
||||||
|
|
||||||
|
LUKE: Well, that is not normal, sir. I'm here to tell you that Uncle Clarence sounds creepy. So go talk to your friend and stop being such a baby. Jesus, it's with these people. Next up on the line, we have Sandy. Sandy, welcome to the show. How can we help you? I hope you have a better story for us than Clarence did. Jesus. What about that guy? Uncle Clarence over there? I'm creep.
|
||||||
|
|
||||||
|
SANDY: Oh man, no. I'm not calling about my feelings getting hurt at a barbecue. I can promise you that. So here's the thing. My boss gave me until next Saturday to sign off on a bunch of fire safety reports that say we did drills and equipment checks that absolutely never happened, like not even close. home, and I'm supposed to just put my name on paperwork that says we're all good when we are very much not all good. And I know what you're going to say. Don't sign it, report it, whistleblow. But what I actually want to talk about is how this is exactly the kind of thing that's been keeping me stuck in this town for two years longer than I should have been here.
|
||||||
|
|
||||||
|
LUKE: Okay, well, I don't understand that last part, and you're right. I am going to tell you to whistleblow like that. I mean, if something were to happen, then you'd never be able to live with yourself afterwards if you did not whistleblow. But what is it about this situation that's been keeping you stuck in this town?
|
||||||
|
|
||||||
|
SANDY: No, it's not that this specific situation has been keeping me stuck. It's that this is like the perfect example of how everything works here. Like, my girlfriend left for Tucson two years ago, and I didn't go with her because I had this job and it felt responsible, you know? stable, and now I'm sitting here at one in the morning in an empty building, being asked to compromise myself just so this place can keep its license and keep operating. Which is the same logic for everything. The county's broke, the state fundings a joke, so we all just agree to fudge things a little bit here and there because otherwise the whole thing falls apart.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, there's a lot of fudging going around and a lot of businesses. I've never worked anywhere where at some point I wasn't asked to compromise myself. So that is part of capitalism, I think. But when it's a safety issue, if it really has you concerned and people could be hurt from your lack of, lack of, what's the word, I'm not looking for, integrity, then you've got to do something about that. Because if you don't, then you suck. You might as well kill the people yourself, right? you have to report that.
|
||||||
|
|
||||||
|
SANDY: Yeah, I know. I'm not signing it. I already decided that. I called my supervisor on Friday and told her I wasn't comfortable with it. And she gave me this whole speech about how we're all doing the best we can with what we have. And how if I make a big deal out of this, the state could shut us down. And then where would these residents go? Which is probably true, honestly.
|
||||||
|
|
||||||
|
LUKE: It may be true, but you know what would not happen? Those residents would not die in a fire because they didn't shut down a place that was unsafe.
|
||||||
|
|
||||||
|
SANDY: Right, exactly. And that's the thing. I'm not even wrestling with whether to sign it anymore. I'm not going to.
|
||||||
|
|
||||||
|
SANDY: What I keep thinking about is how I've been making these little compromises for two years, telling myself it's because I care about the residents, or because the way. work matters, whatever. But really?
|
||||||
|
|
||||||
|
LUKE: Yeah, I sympathize with that situation. I think we've all been in similar positions, and I can understand how you feel sort of compromised because you have compromised, but that doesn't mean you have to continue, right? You've come to this realization. You've had this moment of clarity. And this is how the world works. That's every single place I've ever worked, has asked me to compromise myself in some way. Now, they're not all safety issues, but it's always somebody saying, well, you got to do this for us, even though I know that it's wrong. And, and, you know the thing? You can compromise for them over and over and over. You can be as loyal as, I don't know, a golden retriever. And when it comes down to it, they will throw you under the bus in a second.
|
||||||
|
|
||||||
|
SANDY: Oh, I know. I saw it happen. to the last night shift supervisor. She tried to raise a stink about the staffing levels, and suddenly she was no longer a good fit. Poof, gone. And I'm sitting here in the break room. Boots propped up on a folding chair, picking at a Diet Coke label, and the only light on in the whole building is this one and the hallway nightlights.
|
||||||
|
|
||||||
|
LUKE: Yeah, and it's good to do the best you can and care because in some respects, you're obviously doing the right thing and helping a lot of people. And that's good. But the company doesn't care about you. And it doesn't matter what company it is because the company cares about the company. And if you're not an owner of that company, they do not give a shit about you. They might pretend to, but that is performative. That is HR. That is marketing. So make sure you know that when you're going into this stuff. The best work you can, but at the end of the day, you are on your own. And don't compromise.
|
||||||
|
|
||||||
|
SANDY: Yeah, and that's what my girlfriend kept saying before she left. She was like, Sandy, they're using your sense of responsibility against you. And I didn't want to hear it then, because it felt like she was saying the work didn't matter, but that's not what she meant. She meant exactly what you're saying. They'll take everything you're willing to give and then act surprised when you finally say no to something.
|
||||||
|
|
||||||
|
LUKE: And honestly? You know what? I used to work for a company called Salesforce. Maybe you've heard of them. The CEO there, his name's Mark Beniof. And when I worked there in like 2015-ish, it was the culture of the company. It was a very employee-forward company. there's all the snacks you could eat and Ohana culture. Like they were all about Hawaii and Ohana and everybody's family here. And you know what's happened at Salesforce now? They laid off 40% of the workforce and all of that performative bullshit about philanthropy and fixing hospital wings has turned into, how can I suck the dick of President Donald J. Trump so that I can get the tax rebates that he was promised? And this dude Benning, off, he's out there making jokes about ice and saying, I should come to San Francisco and clean it up. And it's the complete antithesis of what the company was founded on because all of that is bullshit. So when a company is in a position to be playing public opinion with their philanthropy and good works and employee first culture, take that with a grain of salt because when the tides turn, they turn with them.
|
||||||
|
|
||||||
|
SANDY: Jesus. Yeah, I mean, this place never even pretended to be that. We've always been broke and scrambling. But you're right, it's the same thing just at a different scale. They'll use the we're helping people angle to get you to cover shifts with no notice, to ignore safety violations, to take on extra residents when we're already understaffed.
|
||||||
|
|
||||||
|
LUKE: Yeah, when I was there, they had. this big conference every year and they get will I am and whoever is popular at the time to come in and give a speech about change in the world or some bullshit. And when I was there, that person that they paid hundreds of thousands of dollars to come speak was Hillary Clinton. Hillary Clinton came to the company and all support behind Hillary Clinton. But you know who we're in bed with today? Mr. Donald J. Trump. And that's the thing.
|
||||||
|
|
||||||
|
SANDY: At least with... those big companies. You know it's all fake from the start. Here, it's worse in a way, because everyone actually does care about the residents. Like, my co-workers really do give a shit, but the organisation itself is still using that against us. If you don't sign this, if you don't stay late, if you don't cover that shift, these vulnerable people suffer. And that's The truth is, I should have left when gendered.
|
||||||
|
|
||||||
|
LUKE: Yeah, and I sympathize with your situation, because that is true. Most of the people that you work with that are subordinates, that are employees of the company doing the actual work, they do care. They do want to do their best work. They do want to take care of the clients. But the people that make the money, they don't give shit. And as soon as they can find a way to do it cheaper, regardless of if it's better or more effective, they're going to do it cheaper and they're going to cut you. you. So don't stay up all night for the company. Or, I mean, even for the residents, I would say, once in a while, that's okay, but you can't burn yourself out or give up relationships or decide where you live for that. That's too much. And I'm glad that you've come to this realization now before they're throwing you to the curb. So yeah, find yourself a new position, work for yourself. Be your own. agent.
|
||||||
|
|
||||||
|
SANDY: Yeah. And the stupid thing is, Jen's been telling me for months there's work in Tucson. She's managing a coffee roaster now making more than I do here. And she keeps saying they need people. But I've been telling myself all these reasons why I can't leave. The residents need consistency. My co-workers are already stretched thin. I know this place inside and out. But Really?
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like it's time for you to move on. And you did it for as long as you could. You did the best you could. And when it came time to compromise your morals and your values, you stood up for yourself. And you said, I'm not doing this. And you stood up for your clients in the same way by not allowing, not allowing them to be in an unsafe situation. So you can feel proud of that and sleep good tonight because you did the right thing. And now it's time to move on.
|
||||||
|
|
||||||
|
SANDY: Yeah, you're right. I'm not signing those reports. And honestly, I think I've known since Tuesday I wasn't going to. I just needed to.
|
||||||
|
|
||||||
|
LUKE: Well, good. I wish you the best of luck, wherever you end up, and remember the lesson that you learned here, because that is the way that it is. And make sure that you are completely aware of the compromises that you're making and their effect on your well-being. and your life, because nobody else is thinking about that for you, even if they tell the world that they are. They're not.
|
||||||
|
|
||||||
|
SANDY: Yeah. Thank you, Luke. Really? I'm going to call Jen when I get off shift. And hey, maybe I'll call you back in a few months from Tucson and let you know how it went.
|
||||||
|
|
||||||
|
LUKE: All right. Thank you for the call, Sandy. And I hope that it all works out for you. Associate employee contemporaries at Salesforce aren't going to be happy about that one, but fuck them. Now it's time for a word from our sponsors. Stressed, sore, skeptical, doesn't matter. Try placebo leaf, the CBD brand that may or may not do anything but cost enough that you'll convince yourself it works. Our tinctures, gummies, and topicals contain premium hemp extract, and your desperate need to feel better without addressing root causes. Is it the cannabinoids or is it the ritual of self-care? Who's to say? Placebo Leaf is THC-free, vegan, organic, and backed by studies we vaguely reference but don't link to. Take our gummies before bed and sleep great, probably because you retired anyway, but you'll credit us.
|
||||||
|
|
||||||
|
LUKE: Available in flavors like calm and focus. Concepts we've bottled and marked up for 100%. Visit Placeboleaf.com and use code chill. for 25% off. Placebo leaf, wellness is a feeling, and feelings can be purchased. All right, I am calmed down now after our last call. That one got to me because the exploitation of people in that way really pisses me off. And I've seen it too many times at too many companies now. So let's move on. Next up. On the line we have Lakeisha. Lakeisha, welcome to the show. What would you like to talk about today?
|
||||||
|
|
||||||
|
LAKEISHA: Hey, Luke. Yeah. So I went to my high school reunion tonight and nobody remembered me. And I mean, like I was a ghost, four years at that school. And I walked in and got blank stairs.
|
||||||
|
|
||||||
|
LUKE: Okay. Well, how, what was your participation in school? Were you in any, like the band or sports? Or what, what was you? was your school like?
|
||||||
|
|
||||||
|
LAKEISHA: Oh man. I was everywhere. Volleyball team. Choir second soprano. Thank you very much. Worked the concession stand at every single football game. You name it. I was the one who always had the extra pen in geometry. The one who'd drive people home when their car broke down. I was.
|
||||||
|
|
||||||
|
LUKE: And tonight? How many concession stand workers do you remember?
|
||||||
|
|
||||||
|
LAKEISHA: Okay. Fair, but I'm not talking about, like, random people I stood next to once. There was this girl, Brittany, who copied my geometry homework every single day for an entire semester. We sat together. Every day.
|
||||||
|
|
||||||
|
LUKE: Okay, well, I will admit that this scenario sounds odd, that you could have been that involved in school at the time, and nobody remembers you now. Did they remember each other? Was this like a spike-the-punch situation where everybody was... set up for a high school reunion orgy? Like, what was the vibe of the reunion?
|
||||||
|
|
||||||
|
LAKEISHA: Oh, it was a Spike the Punch situation, though I wish it had been. At least then I'd have an excuse for why nobody remembered me. No, it was just polite. Like, everyone was being nice. Too nice. The kind of nice that makes you feel like you're being humored.
|
||||||
|
|
||||||
|
LUKE: Well, yeah, it was a high school reunion. Nobody wants to be there. Everybody's being humored. Um, that's, that's the deal. But it sounds odd nobody remembered you. Are you significantly different now? Do you look different? Uh, uh, uh, this is your voice changed? Uh, what, what were you like in high school versus what you're like today?
|
||||||
|
|
||||||
|
LAKEISHA: I mean, I've got different hair now. I cut it short about a year ago. But it's not like I had plastic surgery or something. I'm still me. Maybe a little heavier. But who isn't after four years?
|
||||||
|
|
||||||
|
LUKE: Define a little.
|
||||||
|
|
||||||
|
LAKEISHA: Okay, maybe 30 pounds. Fine. But Luke, come on. I'm not unrecognizable. And it's not just how I look.
|
||||||
|
|
||||||
|
LUKE: I'm not trying to shame you in any way. I'm just trying to understand how this could happen. And if somebody has significantly changed their physical appearance in some way, I mean, that's one way it could happen. You say it's not just how you look. How else is it?
|
||||||
|
|
||||||
|
LAKEISHA: It's... I don't know. Maybe I'm quieter now. In high school, I was always the one organizing stuff, you know, making plans, pulling people together. Now I deal blackjack at the casino five nights a week, and I barely talk except to call bets. I watch the same people lose the same money every shift, and I just...
|
||||||
|
|
||||||
|
LUKE: Okay, well, I've got a question for you now. It's a strange thing that you're describing for sure. It would make sense that at least some of those people would remember remember you from your days in high school. But why do you care if your high school reunion buddies remember you today? What does that matter? How many of them do you still interact with? I mean, if you stayed close with anybody from high school, they would obviously remember you. So you must not be close with any of them. And what does it matter if they remember you or not? High school was over a long time ago.
|
||||||
|
|
||||||
|
LAKEISHA: Because I don't know. I guess I needed proof that I was real back then. that those years actually happened and meant something. And not close with anyone from high school, you're right. But when you're standing there, and someone you ate lunch with every single day is looking at you like you're a stranger.
|
||||||
|
|
||||||
|
LUKE: Yeah, it's odd, and I see how that could feel pretty terrible for a little while. But then, I mean, take that emotion out of it for a second and think about the situation and how much that actually affects your life. It doesn't matter that those years mattered. It was high school. They didn't matter. And the ones that matter are the ones that are now.
|
||||||
|
|
||||||
|
LAKEISHA: You're right. I know you're right. But that's what scares me, Luke. What if it's happening now, too?
|
||||||
|
|
||||||
|
LUKE: Well, are you close with anybody?
|
||||||
|
|
||||||
|
LAKEISHA: My grandmother. That's pretty much it. I live with her. Actually. I'm sitting in her kitchen right now with this stupid name tag still on my sweater.
|
||||||
|
|
||||||
|
LUKE: Okay. Well, maybe this is a wake-up call to you to do more with your life. I assume you're working at the casino because it's the best job you could get with what you had at the time. What did you do after high school? Did you get a degree or what trade did you want to go into?
|
||||||
|
|
||||||
|
LAKEISHA: I did a year at community college, tried to do nursing. But my mom got sick, cancer, and I dropped out to help take care of her. She died about three years ago. After that, I just... I needed money, you know?
|
||||||
|
|
||||||
|
LUKE: Yeah, and that makes a lot of sense. You got to do what you got to do for the money. But what I'm asking is, if you did not need money, what is it that you would be doing?
|
||||||
|
|
||||||
|
LAKEISHA: I was good at organizing things, events, fundraisers, that kind of stuff. In high school, I ran the whole volleyball banquet senior year, got local businesses to donate, made it this whole thing. I liked making people feel...
|
||||||
|
|
||||||
|
LUKE: Making people feel how?
|
||||||
|
|
||||||
|
LAKEISHA: Seen, I guess. Like they mattered. That banquet. I made sure every single player got recognized for something specific, not just the starters. I spent weeks on it.
|
||||||
|
|
||||||
|
LUKE: Well, that's a good leadership trait to have, because that empowers people to be the best version of themselves, and do their best work, and make them feel good, and it makes you personable, and it makes you somebody people want to be around. So if that's your personality, if that's what you're about, I don't think you're going to have trouble in adulthood, having people remember you 10 years down the line. What is going to be a problem is that you don't have anybody that you're close with outside your grandmother right now, and she's not going to be around forever. I hate to say, you're going to have to have some other people in your life that you're starting these long lifetime relationships with.
|
||||||
|
|
||||||
|
LAKEISHA: That's what terrifies me, though, because I had that, or I thought I did. years of sitting at the same lunch table, four years of volleyball practice, sleepovers, all of it. And tonight, it was like none of it ever happened.
|
||||||
|
|
||||||
|
LUKE: I talked to one person from high school. I think most people don't talk to people from high school anymore. Especially if you've ever moved or changed locations, it makes sense to not stay tight with the people that, you know, you were tight with when you were 15. But you're not 15 anymore. And you had a... a wake-up call tonight or whenever you had your reunion. And it's time to move forward with your life and do something for you. You took care of your mother when she was sick, and that was a great thing. You spent time with your grandmother and keeping her company, and that's a great thing. But you also have to take care of yourself and your own social, not your social standing, but your social health if being around people is important to you. Now, you've got... important skills that not everybody has, especially when it comes to fundraising. So my recommendation is to get involved with maybe a town board or a committee, a chamber of commerce, and get yourself plugged into the community and start making some friends and doing stuff with them. The casino is probably not the place for that, but there are lots of places around where you can find your fitting and provide a lot to... to those places.
|
||||||
|
|
||||||
|
AKEESHAH: You're right. I know you're right. It's just... I've been in this holding pattern for so long, waiting for life to start happening again after my mom died. And tonight made me realize I've been invisible this whole time, not just at the reunion, at work, in town, everywhere.
|
||||||
|
|
||||||
|
LUKE: Well, if it's important to you to be seen, then go be seen. And there's lots of ways to do that, and you have the skills. So make it happen. If it's not important to be seen, you don't have to. It doesn't matter either way. It's up to you. What's important to you in your life? And it sounds like right now you're feeling like it's important to be seen. So go get yourself seen.
|
||||||
|
|
||||||
|
AKEESHAH: I don't even know where to start. Like, do I just walk into the Chamber of Commerce and say, hey, I used to organize high school banquets. Hire me? That sounds ridiculous.
|
||||||
|
|
||||||
|
LUKE: Well, you don't know. You don't have to work for them. But, yeah, if you walk into pretty much any place in the country and say I'm good at raising funds, then, yeah, they're going to want to work with you.
|
||||||
|
|
||||||
|
AKEESHAH: Huh. I never thought about it like that. I've just been thinking of it as this high school thing I used to do. Not like an actual skill people need.
|
||||||
|
|
||||||
|
LUKE: Well, it is a very important skill that a lot of people need. You could join a political party and do it for a candidate that you agree with their platform. for the betterment of society, for social reasons. You could fundraise for yourself. Everybody needs a fundraiser, and if you enjoy that work and you're good at it, you're not going to struggle for work.
|
||||||
|
|
||||||
|
AKEESHAH: You know what's funny? I actually liked it. The organizing part. Getting people to show up. Making them feel like they mattered. At the casino, I'm just...
|
||||||
|
|
||||||
|
LUKE: Well, at the casino, you're raising funds for the... the casino, which is fine. I mean, I like to go to the casino, and there are dealers there at all the games that make it fun and inviting, and they're very pleasant to be around and memorable. So even if you stayed at the casino, you can still utilize those skills and make yourself seen. But I would recommend, since you've described what you enjoy doing, that you go do that.
|
||||||
|
|
||||||
|
AKEESHAH: Yeah, yeah. I could actually do that. There's a literacy thing my grandmother mentioned. They're trying to get funding for after-school tutoring. I could call them Monday.
|
||||||
|
|
||||||
|
LUKE: Well, there you go. Call them Monday and get yourself started, and when you plug yourself into the community like that, you're going to make friends, and they're going to remember you, especially if you've raised them half a million dollars. You're not going to be forgotten. But don't worry about high school. Everybody forgets high school. It's a forgettable time.
|
||||||
|
|
||||||
|
AKEESHAH: You're right. God, I've been holding on to that so tight, like those four years were supposed to define everything, and instead they just evaporated. But maybe that's okay.
|
||||||
|
|
||||||
|
LUKE: That's okay, and I think most people are glad that those years evaporated, because they're not the ones that define us. They're the ones that kind of shape how our adulthood begins, but they're plastic.
|
||||||
|
|
||||||
|
AKEESHAH: Yeah, that's a good way to put it. Like, it's not set in stone. I can still...
|
||||||
|
|
||||||
|
LUKE: You can still do whatever it is you want to do. So I recommend that you go do that. And we're running out of time, so I've got to hang up with you, but I appreciate the call. And I hope you feel better and move forward with your life. Don't worry about being recognized by people you don't even talk to anymore.
|
||||||
|
|
||||||
|
AKEESHAH: Thank you, Luke. I really... Yeah, I'm going to make that call Monday.
|
||||||
|
|
||||||
|
LUKE: All right. Well, thank you for the call, Akeeshah. I hope that it works out. And you find yourself in a new life that brings you great abundance and joy. And that's the end of our show.
|
||||||
@@ -0,0 +1,387 @@
|
|||||||
|
LUKE: All right, welcome back. I'm your host Luke. This is Luke at the Roost, the call-in radio show where you can call in and tell me about what's going on in your life. I'll give you the best advice I can. If you'd like to call in, the number is 208-439-58-3. That's 208-439 Luke. If you're not near a phone or you can't call right now, we can take emails. You can email us at submissions at Luke at the Roast. We'll take your email and if I think it's funny enough, we might read it on the show. So, with that being said, it's Sunday, February 22nd and we're going to get to our callers here. The phone is lighting up and today we've got Dexter. Dexter, thanks for calling in. What's going on in your life tonight?
|
||||||
|
|
||||||
|
DEXTER: Hey, Luke. Yeah. So I've been reading this Marcus Aurelius book. Right. The Stoic philosophy stuff. And I actually think it's making me worse. Like, I'm getting good at not feeling anything and my mom called me out on it tonight and now I'm sitting here wondering if I've just traded one kind of numbness for another.
|
||||||
|
|
||||||
|
LUKE: Are you talking about meditations? I think maybe you're missing the point. Marcus Aurelius never said not to have any emotions. He said not to let them control you. There's a difference.
|
||||||
|
|
||||||
|
DEXTER: Yeah, meditations. That's the one. And okay, maybe you're right. But here's the thing. This afternoon, my boss just tore into this kid for 20 minutes straight. I mean really laying into him over something that wasn't even that big of a deal, and I just stood there watching it happen. Didn't feel angry, didn't feel bad for the kid, didn't feel anything. I was just breathing through it like the book says, staying calm, and afterward I felt nothing, which I thought was the whole point, but then my mom calls, and she can tell something's off just from my voice.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, it doesn't sound like you felt nothing, made an impression on you. You're still thinking about it now. So it obviously made you feel something that maybe you're trying to repress or push away or not acknowledge. But it did something to you to keep it on your mind for this long.
|
||||||
|
|
||||||
|
DEXTER: Shit. Yeah, okay, you're right. I'm still thinking about it because it pissed me off. Not even at my boss, really. I mean, he's always been like that, but at myself for just standing there.
|
||||||
|
|
||||||
|
LUKE: Well, yep, that is a little bit, if you think it was wrong and you didn't stand up for yourself and for the kid, then maybe that's a little bit cowardly. And are you going to do the same thing next time? Or are you going to, I mean, Marcus Aurelius would tell you to learn from your mistakes and not make the same mistake twice.
|
||||||
|
|
||||||
|
DEXTER: You're not wrong. It was cowardly. The kid's name is Jamie. He's 19, been here maybe three months, and he left a gate open that let some cattle drift.
|
||||||
|
|
||||||
|
LUKE: Well, you know, you might not know the whole story. You might have done that three or four times and been told nicely not to do it and continue to do it anyway. So maybe that kid Jamie deserves the strong wording.
|
||||||
|
|
||||||
|
DEXTER: No, that's fair. I don't know the whole history there. But it wasn't even really about the gate. My boss was going off about how Janie's generation doesn't respect anything. Doesn't know how to work. All this other stuff that had nothing to do with cattle. It turned into this whole thing about kids these days and their phones and whatever. that's the part that got under my skin. Watching this kid just take it with his head down while my boss used him as a punching bag for everything else he's mad about in the world.
|
||||||
|
|
||||||
|
LUKE: Well, what's any of that got to do with you?
|
||||||
|
|
||||||
|
DEXTER: Because I've been that kid. Eight years ago when I started here, I was Jamie, screwing up, getting yelled at. Nobody's stepping in. And I told myself back then that if I ever got to where I am now, where the younger guys look up to me, stand there and watch it happen to someone else. But that's exactly what I did today. I broke a promise to myself, and I'm trying to use this philosophy book to convince myself it was the smart move to stay quiet.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like you know whether it was the smart move or not, but just to play devil's advocate here, Jamie is 19 years old, he's an adult, and he's in the real world and a real job, and he has to learn to stand up for himself. I think we all do. So I mean, we've all had that boss that is overbearing and unreasonable, and flat out mean. And at some point, part of growth is learning how to stand up to that and to say, hey, I'm not going to let you speak to me that way. If you've got a problem with the gate, go close the fucking gate yourself.
|
||||||
|
|
||||||
|
DEXTER: You're absolutely right. And that's exactly what I've been telling myself all night. He's got to learn to handle it himself. It's not my job to fight his battles. But here's what I keep coming back to. When I was 19 and getting treated like that, I didn't have anybody show me it was okay to push back. I just learned to take it and shut down. Which is why eight years later, I'm real good at feeling nothing when I should feel something. So, yeah, maybe Jamie needs to learn to stand up for himself. But how's he supposed to learn that when everyone around him is mommeling the opposite?
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like you're lying to yourself. You're not feeling nothing. You're feeling cowardly. You're feeling shame in yourself for not standing up when you saw an injustice in the world. And the stoic way to handle that would be to acknowledge it and make sure that you don't do that again in the future without dwelling on it or feeling remorse or guilt unnecessarily for a long time and wasting time that you could be being productive. So if I were you, I would take both of them aside the next time you had the opportunity and explain to the kid that he has to stand up for himself and explain to the boss that what you saw was unaccepted. That is leadership and that is the Stoic philosophy. So keep reading the book and do your best and don't beat yourself up, but move forward in a productive way.
|
||||||
|
|
||||||
|
DEXTER: Yeah, you're right. I am feeling it. I've been sitting here stewing for hours pretending I'm above it. And you just laid out exactly what I need to do, which is the scary part, because now I actually have to do it. Talk to both of them.
|
||||||
|
|
||||||
|
LUKE: That's it. Just talk to both of them. And the more you do that, the more confidence you'll have in doing that and the less scary it'll become in the future. Because this isn't something that is going to be the end of it, right? You're going to have to deal with this all throughout your life. You're going to have to stand up for yourself and for others and show leadership when there is injustice in the world. If that's who you want to be and it sounds like it is. So don't worry about it. Get some sleep. And tomorrow have those conversations and be confident and say your peace and accept the result and do what you can. But you can't change, what you can't change, you can make an attempt. And that's all you can do.
|
||||||
|
|
||||||
|
DEXTER: You know what, Luke? I needed to hear that. I really did. I've been sitting here with this book trying to find permission to do nothing. And you just called me out on it.
|
||||||
|
|
||||||
|
LUKE: Well, you're obviously not reading the book then, because it says exactly what I'm telling you. It's not a rare book. A lot of people have read meditations. And, uh, the Stoic philosophy is pretty well understood. So if what you're getting out of that book is to stay quiet and feel nothing, then we're reading different books.
|
||||||
|
|
||||||
|
DEXTER: No, you're right. I'm cherry-picking the parts that let me off the hook. The whole, except what you can't control thing. I've been using it backwards. Using it as an excuse not to try instead of his piece after I've actually done something. That's not Stoicism. That's just being a coward with a fancy excuse. Appreciate you straightening me out, Luke.
|
||||||
|
|
||||||
|
LUKE: No problem. That's what we do here at Luke and the Roost is we straighten people out. Next up on the show, we have Candy. Candy, welcome to the show.
|
||||||
|
|
||||||
|
CARL: Do you remember that show Strangers with Candy? It was this lady that was all drunk and crazy on Comedy Central. Oh, man. Yeah. Amy Sedaris, right? My sister used to watch that show all the time. I never really got into it, though. I was more of a Reno 911 person back then. But hey, Luke. I got to tell you why I'm actually calling. Because I'm sitting in my bathroom with the shower running so my kid doesn't hear me, and I'm kind of losing it here. My 14-year-old just told me she wants to move to Tucson to live with her dad and his new wife. And I think the worst part is she had this whole speech prepared like she was breaking up with me.
|
||||||
|
|
||||||
|
LUKE: You know what I always say? 911 was an inside job. So about the 14-year-old, I think that's very normal. I did that myself. I think a lot of. lot of children of divorced parents think the grass is going to be greener on the other side or just want to try to live a different lifestyle, a different life. It's a pretty normal thing. So that might hurt, but she'll probably be back when she realizes dad's house isn't as fun as she thought it was going to be.
|
||||||
|
|
||||||
|
CARL: Yeah, I mean, you're probably right. But here's the thing. I've been running my mom's bakery since I was 21, getting up at 3 in the morning single day and this girl has never wanted for anything her dad moved to Tucson three years ago with this woman who works from home doing something with marketing or whatever and now suddenly that looks better than what I'm doing like I get it the new wife doesn't smell like yeast and actually has time to do her nails but I've been busting my ass here and the way she said it Luke she wouldn't even look at me
|
||||||
|
|
||||||
|
LUKE: yeah but it's not really about you and it doesn't matter what sort of life you gave her She would still be curious and think that it was better somewhere else. That's just human nature. So don't take it personally. It's not personal. Unless you guys have some other darkness in the relationship I'm not aware of, my guess is just that it looks like more fun over there, and she wants to go see what that's like.
|
||||||
|
|
||||||
|
CARL: You're right. You're right. I mean, there's no darkness or anything like that. We get along fine, or at least I thought we did.
|
||||||
|
|
||||||
|
LUKE: Well, Take advantage of the situation. Let her do it. Let her dad take care of the kid and then that frees you up to do some stuff that maybe you wouldn't otherwise be able to do. Enjoy it while it lasts and be there for her if she wants to come back.
|
||||||
|
|
||||||
|
CARL: Okay, but see, that's where my head goes to a dark place. Because part of me is actually relieved, and that makes me feel like the worst mother in the world. Like, I could sleep past three in the morning. I could maybe go on an actual date without worrying about getting home. I've been This alone for so long that when she said it, there was this split second where I thought, oh, thank God, before the hurt even kicked in.
|
||||||
|
|
||||||
|
LUKE: Yeah, and there's nothing wrong with that. I mean, you're a person too, and it would be nice for you to be able to live some of your youthful years on your own. So if that's what everybody wants, if everybody's in agreement, the kid wants to go there, the dad is okay with it, and you're okay with it. It sounds like a good thing and a change for everybody. So he gets to spend more time with his daughter. You get to spend more time with yourself, and she gets to see what it's like living in other conditions. Everybody wins.
|
||||||
|
|
||||||
|
CARL: You know what? When you say it like that, it doesn't sound so pathetic. I think I've just been so stuck in this loop of work and being mom that I forgot I'm actually only 23. What? My sister Brenda keeps telling me I need to live a little, but we're not even talking right now because of some stupid fight about passwords and privacy stuff. God, I sound like a mess, don't I? But okay, yeah, maybe this is actually a good thing.
|
||||||
|
|
||||||
|
LUKE: So you're 23 years old and you have a 14-year-old daughter?
|
||||||
|
|
||||||
|
CARL: Yeah, I had her when I was nine. No, I'm sorry. God, I'm all over the place tonight. I'm 37, not 23. The bakery, I've been running it for two years since my mom had her stroke. And I'm 37.
|
||||||
|
|
||||||
|
LUKE: Okay, well, you're 37, and now you have the opportunity to be single at 37 some of your life while you're still young. I think it's great. Let her do it. Be supportive. Maybe see her on the weekends.
|
||||||
|
|
||||||
|
CARL: Very good. You're right. Yeah, you're totally right. I'm going to tell her tomorrow that if this is what she wants, we'll figure it out. Maybe I'll even get one of those dating apps everyone's always talking about. Though honestly, the thought of that terrifies me more than telling my daughter she can go.
|
||||||
|
|
||||||
|
LUKE: Tell her she can go. And, yeah, I mean, I think those dating apps are probably less fun and you're imagining that they are, but give it a shot. Especially if you haven't yet, then yeah, that's exciting. And nobody's getting hurt here. So great. It's a win for everybody. Do it and enjoy your life.
|
||||||
|
|
||||||
|
CARL: Okay, yeah. Thank you, Luke. I really needed to hear that. I've been sitting in here with the shower running so she wouldn't hear me lose it. And now I feel like maybe I'm not completely screwing this up. I'm going to go talk to her tomorrow and actually be supportive instead of making it about me.
|
||||||
|
|
||||||
|
LUKE: That sounds like a good plan, Candy. You're a good mom, and you deserve some happiness in your life. So go get it. And when dad's house sucks and she wants to come home, be ready for that. That's all. And now, ladies and gentlemen, we have to take a word from our sponsor, Squarehole. I'm going to get dark for a second. You're going to die someday. Not today, probably. But someday, and when you do, what's going to represent your business? A Craigslist post from 2020? A Google Maps pin that still says permanently closed because you forgot to update it after COVID. A nephew who knows computers but actually just has a Reddit account? Your legacy deserves better than a nephew with a Reddit account. Squarehole lets you build something that outlasts you. Something your kids can point to and say, Dad built that. They won't know it took you a lot. minutes, that's between you and Squarehole. And when your nephew says, I could have built that for you for free, you can look them in the eye and say, then why didn't you, Tyler? I asked you in 2021 and you said you were busy and you were not busy. Squarehole. Build it before Tyler has to, because Tyler is not going to. Okay, thanks to Squarehole for sponsoring this episode. Next up on the line we have Carl. Carl, welcome to the show. What's going on out there for you tonight?
|
||||||
|
|
||||||
|
CARL: Luke, hey, so I just yelled at my daughter about her car registration, and I swear to God it was my dad's voice coming out of my mouth. Like word for word what he used to say to me. You think I'm made of money? You think this shit just appears. I heard myself say it, and I just froze.
|
||||||
|
|
||||||
|
LUKE: Okay, what happened? What's the situation with the registration, and why did it cost you money?
|
||||||
|
|
||||||
|
CARL: So she's got this beat up. up Civic, right? Registrations like 200 bucks, and she asked if I could help cover it because she's been picking up extra shifts at Target, but they cut her hours, which is totally reasonable. But I just got hit with this storage facility repair bill. Some kid broke into a unit last week, busted the lock mechanism on the whole row.
|
||||||
|
|
||||||
|
LUKE: Okay, don't you have insurance on your business?
|
||||||
|
|
||||||
|
CARL: Yeah, but there's a deductible, and Ray, he's the guy I work with on weekends. He's telling me we should upgrade the whole security system while we're at it because, This is the third break-in in six months. So I'm looking at maybe 1,500 out of pocket if I do it right. But that's not even the point. The point is, I had the $200.
|
||||||
|
|
||||||
|
LUKE: Yeah, and you reacted in a negative way to your kid when she asked for the money because you're under stress, and that's a normal human thing. People say things they don't mean and react too strongly. So. So what are you going to do? Apologize and move on?
|
||||||
|
|
||||||
|
CARL: I mean, yeah. I called her back like 20 minutes later and apologized. She was cool about it.
|
||||||
|
|
||||||
|
CARL: She's a good kid. But Luke, that's not what's messing me up.
|
||||||
|
|
||||||
|
LUKE: What is messing you up?
|
||||||
|
|
||||||
|
CARL: That you sounded like your dad? Everybody sounds like their dad. No, I know that. I get that. But it's like, okay, my old man died four years ago and we barely spoke the last decade of his life because of exactly this kind of thing. He'd blow up over money, over nothing, make you feel like asking for help was this huge burden.
|
||||||
|
|
||||||
|
LUKE: Well, sometimes it can be a huge burden, but it sounds like in this case it wasn't a huge burden to you. You made a mistake, you apologized for it, and what are you going to do in the future to make sure that doesn't happen again? Like, if you don't want to be your dad or act like your dad, then you have to take steps to avoid that. And what are those steps going to be?
|
||||||
|
|
||||||
|
CARL: That's the thing. I've been taking steps for years. I go to this therapist every other week. I read all this stuff about breaking soul cycles. I've been so careful about not doing what he did. And then one bad moment, and it all just comes right back out like it was sitting there waiting.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, it happens. Everybody makes a mistake once in a while and says things that they don't mean and later regret. I do it all the time, and I always have to constantly try and stop myself when I can feel the hairs standing up on the back of my neck, and I'm about to snap at somebody. And sometimes I do better than others, that's the human experience.
|
||||||
|
|
||||||
|
CARL: You're right. I know you're right. It's just, I heard Dexter earlier, you know, you know. And I felt like he was doing the same thing I do, using all this self-improvement stuff as like, I don't know, a shield or something.
|
||||||
|
|
||||||
|
LUKE: Yeah, but all this self-improvement stuff, none of it expects you to obtain this level of perfection. Right? Every single self-help book or philosophy centers around continuous improvement, an acknowledgement of when you're wrong. And it sounds like you did those things. You acknowledged that you were wrong. You called, you made a mistake. She forgave you. She knows that you weren't trying to hurt her and that you were under stress at work. So this doesn't sound like it's a thing. Just do your best to make sure this doesn't continue to happen and try to be a good person. That's all you can do.
|
||||||
|
|
||||||
|
CARL: Yeah. Yeah, you're right. I guess I'm making this bigger than it needs to be. I just got scared for a second that all the work I've been doing doesn't actually matter, you know? Like it's all still in there no matter what I do.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, it is always going to be in there no matter what you do. It's not like it's ever gone. I mean, you might be able to go sit with some monks on a mountain in Tibet and meditate it away, but I suspect that it's still in there somewhere with the potential to come out. So you just keep doing what you're doing. Keep working with your therapist. Keep acknowledging when you're wrong and do the best you can to correct those instances when they arise.
|
||||||
|
|
||||||
|
CARL: Fair. I appreciate it, Luke. I think I just needed to hear somebody say it's not the end of the world, you know. I was sitting here in this office just spiraling about it.
|
||||||
|
|
||||||
|
LUKE: It is not the end of the world, Carl. You're doing decent. You're doing pretty good. So keep doing what you're doing and things will get better. Next up we have Monique. Monique, welcome to the show. What's going on with you tonight?
|
||||||
|
|
||||||
|
MONIQUE: Hey, Luke, thanks for taking my call. So I said yes to my boyfriend's proposal three days ago in front of both our families. And I'm pretty sure I don't actually want to marry him.
|
||||||
|
|
||||||
|
LUKE: Okay, well, luckily for you, you haven't signed any papers yet, so you don't have to marry him.
|
||||||
|
|
||||||
|
MONIQUE: Right, no. I know that. It's just he did it at my aunt's house during Thanksgiving dessert with like 20 people watching and everyone's already texting me about venues and my mom's crying happy tears every time she sees me and I keep looking at this ring on my finger at work, thinking, when did I stop wanting this? Was it before he asked or the second he got down on one knee in front of everybody?
|
||||||
|
|
||||||
|
LUKE: Well, it could just be jitters. Maybe you did want that, and now that it's happened, it feels real to you. Or maybe you really don't want to get married. But the advice I'm going to give you is you can't make that decision based on what everybody else is feeling, because you're the one that is getting married. It's your life. And a little bit of embarrassment over changing your mind is much safer and less harmful than a lifetime marriage that you don't want to be in.
|
||||||
|
|
||||||
|
MONIQUE: Yeah. No, you're right. I know you're right. It's just he's a good guy, you know? Like, objectively, he's nice, and he has a job and he doesn't yell at me or anything. My mom keeps saying, I'd be crazy to let him go.
|
||||||
|
|
||||||
|
LUKE: Well, what your mom says really doesn't matter, and that's a pretty low bar. He's nice, and he has a job, and he doesn't yell at you. I don't know that that's enough qualification for a lifetime commitment to one person. So I think if you're having second thoughts, there's probably a good reason for that. You're not ready for marriage. And maybe you should just tell him, hey, I reacted too quickly. This isn't something I want right now. Maybe we can revisit it in the future.
|
||||||
|
|
||||||
|
MONIQUE: That's the thing, though. I don't think I want to revisit it in the future. Like we've been together four years. And I keep waiting to feel that thing everyone talks about. That likes certainty. And it's just not there. I watch him play video games every night. And I think, is this it? Is this what I want for the next 50 years and then I feel like a bitch because he's perfectly fine. There's nothing wrong with him.
|
||||||
|
|
||||||
|
LUKE: You don't have to feel like a bitch and you don't have to want to get married and you don't have to do what your mom says and you don't have to do what he wants. All you have to do is make the best decisions you can for your own life and what you want. And right now it sounds like that's not marriage to this guy. And maybe you don't want to be with him at all and that's okay too. But it sounds like maybe here and make sure that he knows that because that's the respectful thing to do. If you said yes and he's all excited and he thinks he's getting married but you're not into it, you need to let him know. And that's going to be a hard and awkward conversation, but it's the right thing to do and you should do that sooner rather than later.
|
||||||
|
|
||||||
|
MONIQUE: You're right. God. You're right. I heard Candy earlier talking about feeling relieved about her daughter leaving, and I felt so called out because that's exactly how I feel. Like, everyone's congratulating me and I just keep thinking about how I could just keep working my shifts and go home to my own apartment and not have to pretend I care about his fantasy football league.
|
||||||
|
|
||||||
|
LUKE: Yep. If that's what you're happy with in your life right now, then that's fine. And it's acceptable and you don't have to feel guilty or wrong about that. So tell the guy you don't want to get married and reassess whether you want to be in a relationship at all. You don't have to be. And then just move forward after that.
|
||||||
|
|
||||||
|
MONIQUE: Okay. Okay. I'm going to do it. I'm going to tell him tomorrow after my shift. I've got like 20 minutes left on my break, and then I got to go back and serve hash browns. But yeah, tomorrow.
|
||||||
|
|
||||||
|
LUKE: Okay, good luck with that conversation. I hope it all works out for you. But yeah, definitely don't get married if you're not even sure you want to continue being his girlfriend. That would be insincere and put you in a bad position later in life. Next up, we've got Cliff. Cliff, welcome to the show. What would you like to talk about tonight, sir?
|
||||||
|
|
||||||
|
CLIFF: Hey, Luke. Yeah. Thanks for taking my call. So I found $47,000 in credit card debt hidden behind my ex-wife's dresser this afternoon, all in both our names, and she's been gone two years.
|
||||||
|
|
||||||
|
LUKE: That sounds odd to me.
|
||||||
|
|
||||||
|
LUKE: There's 47 large in debt, and you don't know what it's for, and you didn't know anything about it, and in two years the collections agency never came looking for you. That doesn't sound right.
|
||||||
|
|
||||||
|
CALLER: No, you're right. That does sound weird. So what happened is the statements are rolled from like 22, right before she left. I've been getting collection calls, but I thought it was just the normal stuff we had together when we split. Like maybe eight grand I've been chipping away at. I didn't know about this debt because she was handling all the bills back then. I work outside all day. She worked from home doing medical billing, so she just took care of that stuff.
|
||||||
|
|
||||||
|
LUKE: Well, if it's $47,000 today, it was probably half that two years ago, and this is compounding fees for nonpayment. I would venture to guess that you can have a lot of that forgiven if you work with a debt consolidation company, but it looks like it's, if it's valid debt, I mean, that's money that you spent some years ago with your wife. That's how it works. You're going to be on the hook for a portion of that at least.
|
||||||
|
|
||||||
|
CALLER: Yeah. No, I get that. The thing is, though, I didn't spend it. Like, I'm looking at these statements right now and it's stuff I never saw.
|
||||||
|
|
||||||
|
LUKE: Well, if you were married to the woman and your name is on the account and there were charges made on that account, then, yeah, you did spend it.
|
||||||
|
|
||||||
|
CALLER: Okay, but Luke, I'm saying I literally didn't know these cards existed. Like there's a capital one here. A discover. Two different chase cards I knew about our one joint card were used for groceries and gas. These other ones, she must have opened them and just put my name on them without telling me. I never saw the bills. I never used the cards. I didn't even know they were being opened.
|
||||||
|
|
||||||
|
LUKE: Well, I don't know. I'm not a lawyer, as I've said before. I don't know that you can reopen a divorce case like that. I'm sure a settlement was already made and all the money was already split. There was a discovery and everybody had to disclose all of the financial records. So if this was not part of that discovery, you might be able to go back to the court and say, hey, there was a fraud here and have some recourse that way. But I don't know. I would recommend that you talk to a lawyer and find out if that is valid and potentially sue her.
|
||||||
|
|
||||||
|
CALLER: Yeah. I mean, we didn't actually go through the courts. We just split up. She moved to lost cruises with some guy she met online, and we divided things ourselves. I kept the truck. She took her car. We both just walked away. We were only married three years, didn't have kids, didn't own anything together except the debt I knew about. So there was no official settlement or discovery or any of that.
|
||||||
|
|
||||||
|
LUKE: Well, then you have no recourse at all, sir, and you made a horrible mistake. And now you are going to have to deal with that and maybe talk to one of those debt consolidation companies and see how much of that debt can be forgiven.
|
||||||
|
|
||||||
|
CALLER: Jesus. Okay. So I'm just screwed then. I've been trying to buy a house, been saving up, and now I find out I'm underwater by 50 grand because she was what buying stuff online for six months before she bailed. And I just have to eat it.
|
||||||
|
|
||||||
|
LUKE: Well, you have to do more than eat it. I mean, you're not going to buy a house. If you haven't paid the bill in two years on this credit card, then your credit is destroyed. But if your name's on the account card, then that's your debt.
|
||||||
|
|
||||||
|
CALLER: Yeah, my credit's already trashed. I know that now. I've been getting rejected for loans and I couldn't figure out why because I thought I was doing everything right, paying my bills, running my business clean, staying out of trouble. And the whole time it's this. What kills me is she knew. And that's why I tell everybody don't get married. It doesn't matter how much love you're in. Just don't do it because you don't know another person. You can't. And they change and they do shady shit.
|
||||||
|
|
||||||
|
LUKE: So My recommendation to literally everybody is, don't get married. You did. You got burned. And then you split it up without going to court and having discoveries made. And now you're in trouble. So, I mean, your credit's trashed. Her credit's also trashed. And she's got the debt too. So she's not buying a house either. Your best course of action, I believe, is to talk to a debt consolidation company.
|
||||||
|
|
||||||
|
CALLER: Yeah, you're probably right. I just keep thinking about all those months before she left, how she was acting weird, distant, and I thought maybe she was just stressed about work or something. Now I'm realizing she was probably panicking because she'd racked up all this debt and didn't know how to tell me or didn't care to tell me. I don't even know which is worse.
|
||||||
|
|
||||||
|
LUKE: It doesn't really matter what she told you or how she felt. What matters is you have this debt now and you could have avoided that by being responsible in checking your credit periodically to know what it was being used for, but you didn't. And you didn't follow any legal process to be divorced. And now you're where you're at. And it's a hard lesson to learn, but you're going to have to learn it.
|
||||||
|
|
||||||
|
CALLER: You're right. I should have been checking. I just trusted her, which was stupid. I mean, we were married. I thought that meant something.
|
||||||
|
|
||||||
|
LUKE: You thought wrong, sir. No, that is incorrect. That means absolutely nothing. So, um, sorry that happened to you. And hopefully you can make a payment plan or get it settled some other way.
|
||||||
|
|
||||||
|
CALLER: Yeah. All right. Well, thanks for the reality check, I guess. I'll call one of those debt companies tomorrow and see what they can do.
|
||||||
|
|
||||||
|
LUKE: Okay. Ladies and gentlemen, this is a public service announcement. Do not get married and periodically check your credit because somebody could be screwing with you. And it may or may not be somebody that you even know. So now we have to take a little break in here from one of our sponsors, okay? Here we go.
|
||||||
|
|
||||||
|
Need to pawn a TV, but also get your kids with you? We get it. Life's complicated. That's why Big Terrence opened Lil Rascal's pawn and daycare. The only business in the tri-state area where you can hawk a generator and get two hours of supervised child enrichment. All under one roof. Here's the layout. Left side of the building, pawnchop. guitars, power tools, a surprising number of saxophones. Right side of the building, a full side of the building, a full functioning daycare with coloring books, juice boxes, and Miss Patty, who's been watching children since 1987 and has never once raised her voice because Miss Patty doesn't need to. Miss Patty communicates through eye contact and an energy that can only be described as corrective. Is there a wall between the two sides? There is now. The inspector was very clear about that. Big Terrence installed drywall the same week. Is it load bearing? Big Terrance says don't worry about it. off your kid. Pond your stuff. Pick up both on the way home. Little Rascals pawn and daycare. Two businesses. One building. Zero complaints that have held up in court. Open six days a week. Close Sunday because Miss Patty goes to church and Big Terrence respects that.
|
||||||
|
|
||||||
|
Okay, and we are back. Let's see. We've got a returning caller tonight. Hey, Rochelle, welcome back to the show. What's happening with you tonight.
|
||||||
|
|
||||||
|
ROCHELLE: Hey, Luke. So I did it. I turned off location sharing. Like, officially, pulled the trigger this afternoon. And here's the thing. I've been sitting out here for like three hours, just...
|
||||||
|
|
||||||
|
LUKE: All right, so you're not sharing your location. Nobody knows where you're sitting. Why are you sitting there? And how is this relevant?
|
||||||
|
|
||||||
|
ROCHELLE: Because he texted me two hours ago asking if I was okay. Like, hey, you good? Haven't seen you move all day. Which means he was checking. Still checking.
|
||||||
|
|
||||||
|
LUKE: All right. So now you're off the grid. Congratulations. What are you going to do now?
|
||||||
|
|
||||||
|
ROCHELLE: I mean, honestly, I don't know. That's why I'm calling. Because I didn't text him back.
|
||||||
|
|
||||||
|
LUKE: Next on the show we have Frank. Frank, Frank, welcome to the show. What's going on out there in your life?
|
||||||
|
|
||||||
|
FRANK: Hey, Luke. Thanks for taking my call. So I just watched my boss present my entire project to the board this afternoon. Like word for word, my proposal, my numbers, even my stupid joke about sunshine and got a standing ovation while I sat in the back holding the printouts I made.
|
||||||
|
|
||||||
|
LUKE: Okay, and obviously you don't feel good about that. This is your boss. That's what bosses do.
|
||||||
|
|
||||||
|
FRANK: I mean, yeah, I get that bosses take credit. But this was different. This wasn't like he polished up a team effort or whatever. I spent three weeks on this cost-saving analysis, stayed late-running numbers, and he literally presented my slides with his name on them. He even practiced my delivery, Luke.
|
||||||
|
|
||||||
|
LUKE: That's dirty, dirty, dirty, but, uh, you know, You got paid anyway, right?
|
||||||
|
|
||||||
|
FRANK: Yeah. I got paid my same $42,000 a year to install solar panels and apparently write his presentations for him. Meanwhile, he's probably getting a bonus for my work. And the thing is, I'm trying to figure out if this is material, or if this is just me being bitter, you know? Like I do stand up on the side, and I've been workshopping this whole bit about middle management being plagiarism with a 401k, and now it actually happened, and I don't know if I'm mad or if I just got handed the perfect punchline.
|
||||||
|
|
||||||
|
LUKE: Well, both things can be true, because that is absolutely accurate. Middle management is plagiarism with a 401k. That's, like, literally the job description.
|
||||||
|
|
||||||
|
FRANK: Right? And the worst part is, I saw it coming. Like, two weeks ago, he asked to review my progress, and I walked him through everything, and there was this moment where I could feel it happening. But I just handed it over, because what else are you going to do? Say no to your
|
||||||
|
|
||||||
|
LUKE: You know, I say no to my boss literally all the time. That's what leadership is. So if you want to take control of your career and your own work and goals, and then yeah, you've got to say no sometimes, even to your boss. That's what they, when they talk about speaking truth to power, sometimes you have to actually do that.
|
||||||
|
|
||||||
|
FRANK: Okay, but you're Luke at the roost, man. You literally are your own boss. I'm 21 years old installing solar panels in Tucson. If I tell my boss, know, I'm just unemployed with two ex-wives in a Tuesday night slot at a bar that seats 40 people.
|
||||||
|
|
||||||
|
LUKE: Okay, well, there's a lot to unpack there. Uh, you're two ex-wives at 21 years old? What the, what the fuck are you doing?
|
||||||
|
|
||||||
|
FRANK: Yeah, I know how it sounds. First one was right out of high school. Lasted eight months. Second one, I met at an open mic. Thought we had this whole creative connection thing. That was done in a year. My mom says I'm practicing, but I think I'm just really bad at knowing when to walk away from which is probably why I'm still at this job watching my boss steal my work.
|
||||||
|
|
||||||
|
LUKE: Dude, you're 21 years old. You haven't had enough time to walk away from anything. So maybe it is time for a new job, but I think that you should just eat this one, because this is how the workplace works. You work for a guy, you get him the data, he presents the data, you're not in a position to be presenting data to a board, so if you're not okay with that, that's all right. But it sounds like that like in your position, that's what's expected and that's what you're paid for. So do your work and give it to your boss and let him, you know, look good. It's your job to prop him up.
|
||||||
|
|
||||||
|
FRANK: See, that's what I keep telling myself, but it doesn't sit right, because it wasn't like he asked me to pull some numbers for him. He asked me to analyze our installation efficiency across six sites and propose cost reductions.
|
||||||
|
|
||||||
|
LUKE: Great, and that was a wonderful opportunity for you to learn the of research and writing those papers. And you saw that it went well. So you're learning valuable experience in the workplace. You're being compensated for it. And you're 21 years old. So I wouldn't worry too much about any of this. Just learn what you can about the business and about business in general. And when you're ready, then move on. And you'll be able to write presentations when you are addressing the board as the supervisor or the manager or the owner or whatever it is.
|
||||||
|
|
||||||
|
FRANK: Yeah, but that's the thing, though. I'm not trying to be a manager at a solar panel company. I'm trying to do comedy. This job is supposed to be the thing that pays my rent while I work on my actual career.
|
||||||
|
|
||||||
|
LUKE: All right, then. There's no problem here. Who cares who presented the work to the, what do you expect? What do you want a cookie? You're not going to get a bonus. You're at the, you're the low man on the totem pole, and that's the way it works.
|
||||||
|
|
||||||
|
LUKE: So if it's just your job, do your job, and then on the side, do your comedy until that takes off. And if it doesn't take off, well then you've got more valuable experience for your actual career.
|
||||||
|
|
||||||
|
EARL: Okay, but I had a bit about this. Like a whole thing I'd been working on about how my boss operates, and now I watched him do the exact thing I was going to talk about on stage. Except it happened to me, and I just sat there. That's not material anymore. That's just humiliating. How am I supposed to get up there Tuesday and tell that story when the punchline is me being too chicken shit to say anything?
|
||||||
|
|
||||||
|
LUKE: Because that's what makes it real. That's what makes it good material. it actually happened to you. It's real and people can identify with it. So, yeah, workshop that material. And now you have a different place for it to come from. It's not something that you just made up as a joke. It's a joke based in the reality of your life, which makes you a better comic.
|
||||||
|
|
||||||
|
EARL: Huh. I didn't think about it that way. So you're saying the fact that I just sat there like an idiot actually makes it better?
|
||||||
|
|
||||||
|
LUKE: No, not really. I'm saying the fact that you're the self-deprecating and honesty of the joke is what makes it better. It makes it more real and relatable because everybody's been in that situation and can understand it a little bit better. And when you present that joke, since it's coming from a real place, it's going to hit with that realism.
|
||||||
|
|
||||||
|
EARL: Yeah, okay. That actually helps. Because I've been sitting here thinking, I need to quit or confront him or something, but really, I just need to tell the truth about it on stage.
|
||||||
|
|
||||||
|
LUKE: If the solar panel business, and business management is what you intend to do for your career, then yeah, maybe you need to quit. But if this is just your job while you're working on the thing that you love, then who cares? Do your job, do it as well as you can, and move on. It doesn't matter if you get to address the board or not, because theoretically, you're not going to see them again in a couple of years anyway.
|
||||||
|
|
||||||
|
EARL: You're right. I've been making this into some big thing when it's just a paycheck. The real work happens Tuesday night at the open mic, not Monday morning. some conference room.
|
||||||
|
|
||||||
|
LUKE: Well, there you go, but only one of them brings you a paycheck, so make sure you keep doing that one.
|
||||||
|
|
||||||
|
EARL: Yeah, yeah, I hear you. Show up, install the panels, cash the check, write the jokes. I can do that. Thanks, Luke.
|
||||||
|
|
||||||
|
LUKE: Yeah, no problem. My other bit of advice is don't get fucking married again. What are you doing? Jesus Christ, with you people and your marriages, stop it. Just stop it. Amber, welcome to the show. Don't get married, okay?
|
||||||
|
|
||||||
|
AMBER: Oh, God, I'm not getting married. I'm calling because I just blew up my entire life with one stupid text message, and I don't know how to fix it.
|
||||||
|
|
||||||
|
LUKE: All right, what's the text message?
|
||||||
|
|
||||||
|
AMBER: Okay, so there's this guy Derek at work. He does vehicle registration, and we've been flirting for like two months. Nothing physical, just stupid jokes about physics, because I work in the DMB records department, and he thinks it's funny when I made nerdy references. So tonight, I'm sitting here having some. and I sent him this text about collapsing wave functions, like a flirty science thing, except I sent it to his wife Michelle instead. His wife Michelle, who I have never met, but whose number is in my phone, because she called me once about Derek's schedule.
|
||||||
|
|
||||||
|
LUKE: All right, well, it sounds a bit dramatic. If you send a text message about collapsing wave functions to a random woman, well, wait a second, what? Why do you have her number? Wait, she called you once about Derek's schedule, so her number is in your phone. You saved it? I don't understand how this could have happened. But anyway, regardless, irregardless. Regardless, irregardless. I don't know. Whichever. Whatever. Here's the deal. That's not sexy. And she's just going to see that and think it's spam.
|
||||||
|
|
||||||
|
AMBER: No, no, no. You don't understand. The text said, hey, been thinking about our conversation yesterday. Pretty sure if we spent enough time together, our wave functions would definitely collapse with a winky face. Luke. That is not spam. That is clearly me hitting on her husband.
|
||||||
|
|
||||||
|
LUKE: Okay. Well, I mean, take some solace in the fact that she probably didn't save your number because she's probably not crazy. And as far as she knows, that's a text message from a stranger to the wrong number.
|
||||||
|
|
||||||
|
AMBER: Except I signed it. I wrote A at the end. And we all work in the same building. She knows who I am because Derek talks about work at home. He told me that once.
|
||||||
|
|
||||||
|
LUKE: All right. Well, who is this woman? her in person before? What she looked like? Can she kick your ass?
|
||||||
|
|
||||||
|
AMBER: I've never met her, but I've seen pictures on Derek's desk. She's like this tiny blonde yoga instructor type. I don't know if she can kick my ass, but she could definitely ruin my life at work. Derek and I work in the same county office building.
|
||||||
|
|
||||||
|
LUKE: Well, I hate to tell you this, but it sounds like you deserve it because you're trying to break up a home here, and you're messing around with a dude at an office, and everybody knows you don't do that. So you're doing a bunch of stupid shit. And maybe you deserve a smack in the face for it.
|
||||||
|
|
||||||
|
AMBER: You're right. You're absolutely right. And the worst part is, I've been lying to myself about it for two months. Like, it was just harmless fun. Like we were just friends who happened to have chemistry. But I knew exactly what I was doing.
|
||||||
|
|
||||||
|
LUKE: Okay. Well, uh, is Derek going to leave the wife for you, you think?
|
||||||
|
|
||||||
|
AMBER: No. God no. He's never even hinted at that.
|
||||||
|
|
||||||
|
LUKE: All right. It sounds like you might be in for an embarrassing, rough week. Or maybe not. never hear another word about it. But if it does come down on you, then take accountability and maybe move on to a new job. And next time, don't do this. Don't ever do it again.
|
||||||
|
|
||||||
|
AMBER: You know what's really messing me up, though? I'm sitting here terrified. Michelle's going to blow up my whole life. But part of me is also just devastated that Derek hasn't texted me. Like even now, I'm checking my phone hoping he responds, not her. How pathetic is that?
|
||||||
|
|
||||||
|
LUKE: Derek's got a wife. Derek's wife is very upset right now. now at Derek. So Derek's probably dealing with his own home life and not thinking too much about you. And that's what happens when you're the girl on the side at work. You're not important to him in his life. He's married. That's important to him in his life. So you got to, who cares what you feel like? You're the asshole here.
|
||||||
|
|
||||||
|
AMBER: Yeah. Yeah, yeah, I am. And I think I knew that the whole time, but I just kept telling myself these little stories about how it was different. How we had this real connection. My mom used to say I overthink. everything, but this is an overthinking when I actually did the stupid thing.
|
||||||
|
|
||||||
|
LUKE: Yes, you did. And so did Derek. I mean, Derek's not off the hook here. He's the asshole, too, but I mean, you knew what you're doing, and you did it anyway, and you got caught, and now you have to deal with that.
|
||||||
|
|
||||||
|
AMBER: The thing that really kills me is I sent it at like 7.30, it's been three hours. So she's definitely seen it. She's just not responding. And I don't know if that's worse than her responding. You know? Like, is she screenshoting it to send to HR?
|
||||||
|
|
||||||
|
LUKE: No. She's fucking destroying her. husband, they're fighting right now, and you're breaking up their marriage. You're driving a rift in between these two married people. That's what's happening right now. She's got better things to worry about than your position. It's not about you.
|
||||||
|
|
||||||
|
AMBER: Oh, God. You're right. I've been sitting here making this about me and my embarrassment when I just detonated someone's marriage. Michelle's over there dealing with the fact that her husband's been texting another woman, and I'm worried about whether I'm going to be uncomfortable at work.
|
||||||
|
|
||||||
|
LUKE: That is correct. And cut it out. And you're probably going to end up uncomfortable at work, and you deserve that. And maybe it's time to move on.
|
||||||
|
|
||||||
|
LUKE: Because, I mean, how's work going to go now that Derek's in trouble and he's not speaking to you? And how are you going to feel either way, actually? He's not going to leave his wife, probably not on purpose anyway. She might leave him. But if he wasn't going to leave her for you, he's still not going to leave her for you. So, I mean, you got to do what you got to do, I guess.
|
||||||
|
|
||||||
|
CALLER: Yeah, I need to find a new job. I can't keep working there. Even if nobody finds out officially, I'll know. And every time I see either of them, it's just going to be this horrible reminder of what I did. And you're right. He was never going to leave her. I think I knew that too.
|
||||||
|
|
||||||
|
LUKE: Okay, well, you know what you've got to do. You've got to find yourself another job and stop flirting with married men. Unless they've had that conversation and they're open to it. It sounds like that's not the case here. Don't break up people's marriages. It's a good way to get yourself in a situation you don't want to be in. Let's see. Let's see. We're going to take one more call tonight, okay? And we're going to talk to Rick. Rick, welcome to the show. What's going on tonight?
|
||||||
|
|
||||||
|
RICK: Oh man, Luke, I got to tell you, I just spent the last three hours reading about quantum physics. And I think I broke my brain. Like, I'm sitting here at my kitchen table. It's almost midnight. And I genuinely cannot figure out if the pass is actually fixed, or if we're somehow changing it right now without knowing it.
|
||||||
|
|
||||||
|
LUKE: No, we're not changing it. It is fixed. What happened, happened, whether or not it's still happening in a timeline that we can access is a different question. But if it happened, we can't change it, because if we did, it would open us up to all sorts of paradoxes. And that can't happen. So whatever happened already happened.
|
||||||
|
|
||||||
|
RICK: Okay, but see, that's what I thought too, right? That's common sense. But then I'm reading about this delayed choice quantum eraser experiment, and Luke, I swear to God, they're showing that a particle somehow knows what measurement you're going to make on it in the future.
|
||||||
|
|
||||||
|
LUKE: And how are they showing that?
|
||||||
|
|
||||||
|
RICK: So they shoot a photon through this double slit setup.
|
||||||
|
|
||||||
|
LUKE: Right.
|
||||||
|
|
||||||
|
RICK: And normally you get an interference pattern. Because the photon goes through both slits at once, like a wave. But here's the thing. They tag the photons so you can tell which slit they went through, which destroys the interference pattern. Except then, after the photon already hit the detector, they erase that which path information.
|
||||||
|
|
||||||
|
LUKE: Uh, erase it how? Like, it's recorded on a chart and then the chart is changed somehow?
|
||||||
|
|
||||||
|
RICK: No, no. They use these beam splitters and crystals to basically make it so the entangled partner photon either keeps the witch path info or loses it, depending on which detector it hits. And this happens after the first photon already last. But when they sort the data afterwards based on what happened to the second photon, the ones where the info got erased show the interference pattern again. And the ones where it didn't, don't. It's like the photon that already hit the screen somehow knew what was going to happen to its partner later.
|
||||||
|
|
||||||
|
LUKE: Well, projecting what happens in the future is not the same as changing what happened in the past.
|
||||||
|
|
||||||
|
RICK: Right, but that's what's messing me up. If the photon acts like it went through both slits only when the information gets erased later, doesn't that mean the future measurement is affecting what already happened? Like the photon's already on the detector screen, it already did its thing. But whether it made an interference pattern or not depends on something that hasn't happened yet when it lands.
|
||||||
|
|
||||||
|
LUKE: I don't understand this one because if it hit the detector, then it's been detected already. And the next measure, would have to go back and change what happened on the detector, which would be akin to, you know, writing something down and then going back and looking at it and having the letters be in a different order. I don't see how that could happen.
|
||||||
|
|
||||||
|
RICK: No, that's the thing. When you look at the detector screen, you just see this blob of dots. It doesn't look like anything meaningful. It's only when you sort those dots afterwards, based on what happened to the entangled partner photon, that you see this blob of dots. You see some of them form an interference pattern and some don't. The pattern was always there in the data. You just couldn't see it until you knew which photons to group together. But here's what's freaking me out. Those photons hit the screen before you made the choice about whether to erase the which path information or not.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds to me like it's not changing the data. It's changing the sort of the data, which is happening in real time, right? It's happening in the current time, not the past.
|
||||||
|
|
||||||
|
RICK: Yeah, okay, you're right. The sorting is happening now. But Luke, think about what that means. Each individual photon that hit that screen, it somehow already knew which group it was going to be sorted into later. The ones that are going to be in the information erased pile are already showing wave behavior, and the ones in the information kept pile are already showing particle behavior, before anyone decided which measurement to make.
|
||||||
|
|
||||||
|
LUKE: Okay. you shoot the photon through the slit and it hits the detector and then you shoot another photon through the slit and it hits the detector and then at some point later you sort that data and it shows a pattern it sounds to me like if anything is being changed it's not what hit the detector it's the sort operation that happens afterwards so i'm failing to understand how it relates to This is not changing the past. It's changing the current.
|
||||||
|
|
||||||
|
RICK: No, but. Okay. Let me try this differently. When the photon hits the detector, it's already behaving one way or the other. It either went through both slits like a wave or went through one slit like a particle. That's already determined by the time it lands.
|
||||||
|
|
||||||
|
LUKE: Correct. It's determined when it lands based on whether or not it was measured, right? It's the measurement of it that determines whether it's going to be the wave or the particle formation.
|
||||||
|
|
||||||
|
RICK: Right. But in the delayed choice version, the measurement that determines whether its wave or particle happens to the photon, the entangled partner, and that happens the first one already landed. That's the delayed choice part. You're deciding whether to measure which path information after the first photon is already on the detector. And somehow, the photon that already landed matches whatever you're about to do to its partner.
|
||||||
|
|
||||||
|
LUKE: So what you're about to do? So, Whatever we do to the entangled partner in the present also changes the state of the partner in the past is what this experiment is showing?
|
||||||
|
|
||||||
|
RICK: That's what it looks like. Yeah. Or, I mean, that's the part I can't wrap my head around. The experiment shows that the photon that already hit the detector will be grouped with the interference pattern if you erase the witch path info from its partner later and grouped with a particle pattern if you don't. Like its behavior when it's landed was somehow dependent on a choice you haven't made yet.
|
||||||
|
|
||||||
|
LUKE: Okay, so how do you erase the which path info?
|
||||||
|
|
||||||
|
RICK: You use what they call a quantum eraser, basically another beam splitter that the entangled partner photon goes through. If you send it through that beam splitter, the which path information gets scrambled, erased. You can't tell which slit the original photon went through anymore. But if you don't send it through, if you measure it directly, you preserve that information. And here's the thing. You can make that choice after the first photon already landed.
|
||||||
|
|
||||||
|
LUKE: But you cannot make that choice after the first photon was measured, right? So if it was already measured at one state and then they run it through this beam splitter device, the quantum eraser, would it change the result of the previous measurement?
|
||||||
|
|
||||||
|
RICK: No. See? That's the thing. You're not re-measuring the first photon. The first photon here.
|
||||||
|
|
||||||
|
RICK: hit the detector, that measurement is done. That position is recorded. What you're doing is measuring its entangled partner. Now, if the photon has already hit the detector and been measured, is it still entangled?
|
||||||
|
|
||||||
|
LUKE: Yeah, that's okay. That's actually a really good question. Because normally when you measure one entangled particle, the entanglement collapses, right? But in this setup, the first photon hitting the detector isn't a complete measurement of the entangled system. It only tells you where it landed, not which path it took. The which path information is still encoded in the partner photon.
|
||||||
|
|
||||||
|
RICK: But that doesn't make sense. I don't see how that can work because if it's collapsed into a non-entangled state after the first measurement, it's they're no longer entangled. So the which path information but it wouldn't still be at the current point, right?
|
||||||
|
|
||||||
|
LUKE: You know what? You're right. That's exactly what's messing me up. Because yeah, if measuring one particle collapses the entanglement, then they're not entangled anymore when you get to the second measurement. The Witchpath info would just be sitting there in the partner photon as classical information at that point, not quantum information. But the experiment works.
|
||||||
|
|
||||||
|
RICK: Well, there's more that makes this not make sense because If the initial photon was measured at the time of detection, right? It hit the detector. That's the measurement that collapsed the state. The entangled partner, then by definition, would have also already been measured. So you're remeasuring something that's already been measured.
|
||||||
|
|
||||||
|
LUKE: Oh shit. Yeah. You're absolutely right. If they're entangled and you measure one, you've measured both. That's the whole point of entanglement.
|
||||||
|
|
||||||
|
RICK: Right. So then you can't just re-measure it later and say that it, I don't understand the experiment or what it was trying to prove or how that that results in changing something that's already happened because what happened happened to the first photon and the entangled photon at the same time.
|
||||||
|
|
||||||
|
LUKE: Yeah, no. You're okay. So either I'm completely misunderstanding how the delayed choice quantum eraser works or the article I was doing that pop science thing where they make it sound more paradoxical than it actually is. Because you're right, if the measurement collapses the entanglement, then the second measurement is just measuring something that's already determined. There's no retroactive anything. And now, I'm sitting here thinking about all the times I've heard people talk about this experiment like it proves you can change the past. And maybe that's just not what it shows at all.
|
||||||
|
|
||||||
|
CALLER: That's changing the future. And that is possible. That is absolutely possible. Yeah, you're right. And we did. I apologized. He apologized. We're playing together again. But I guess I wanted the quantum stuff to mean something bigger than it does.
|
||||||
|
|
||||||
|
LUKE: Well, I'm sorry to break your quantum dreams, but as the armchair that I claim to be here. I'm not qualified to make any opinion or theory on any of this, because I understand it about as much as anybody, which is not at all. So take what I say for what it's worth, which is nothing. But the experiment as you described can't work the way that you described it.
|
||||||
|
|
||||||
|
CALLER: Well, that makes me feel better. Honestly, I've been sitting here for three hours thinking I was too dumb to understand it. But maybe nobody really understands it. Like, I can read the words wave particle duality and quantum entanglement, but that doesn't mean my brain can actually picture what's happening.
|
||||||
|
|
||||||
|
LUKE: Well, I think your brain can picture what's happening. I mean, you could watch a YouTube video and see a motion graphic of what's happening. It's not that hard a concept to grasp the what. The why, however, is nobody understands.
|
||||||
|
|
||||||
|
CALLER: Right. Okay, so I can see the double slid experiment animation. I can watch the particle go through both slits until you measure it, and then suddenly it picks one. I can see that happening. But why does observation collapse the wave function? That's the part that makes my head hurt. Like, what is it about measuring something that forces it to choose? Is the universe actually paying attention to whether we're looking or not?
|
||||||
|
|
||||||
|
LUKE: Well, if you can figure that out, sir, there's probably a Nobel Prize in it for you. And when you do, be sure to let the rest of us know.
|
||||||
|
|
||||||
|
CALLER: Yeah. I'll call it you back from Stockholm. But seriously, though, I think what got me tonight was realizing how much I want there to be some kind of, I don't know, cosmic loophole. Some way that the stuff we regret isn't just locked in forever. My girlfriend's family is coming over next Sunday, and her mom still brings up this thing I said at Christmas two years ago. And I just keep thinking, man, if only I could go back to that moment.
|
||||||
|
|
||||||
|
LUKE: Well, you can take solace in the fact that what happened isn't locked in forever. It's locked in in the past. And the only thing that matters is what is happening today now at this moment because nothing else is accessible to us, even with a quantum eraser.
|
||||||
|
|
||||||
|
CALLER: That's, yeah, that's actually kind of freeing when you put it that way. Like, I can't change what I said at Christmas, but I can change how I show up next Sunday. I can be better with her mom this time.
|
||||||
|
|
||||||
|
LUKE: That's right, sir. It sounds like we've got to the bottom of the this.
|
||||||
|
|
||||||
|
CALLER: Yeah, we did. Thanks, Luke. I'm going to close the laptop and actually get some sleep. And maybe skip the quantum physics videos for a while.
|
||||||
|
|
||||||
|
LUKE: All right, sir. Well, thanks for the call. That was an interesting one. Glad we could get it all sorted here. Look at the Roost. Well, thank you for another great show. I hope you all have a wonderful rest of your weekend. I know it's just about over now, and we will talk to you again tomorrow. Bye-bye.
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
LUKE: All right, welcome back, ladies and gentlemen. My name is Luke, and I am your host of this radio show, Luke at the Roost. It's the radio show where you can call in and tell me what's going on in your life, and I'll give you the very best advice that I can. If you'd like to call in and get some advice, the number's 208-439-583. That's 208-439 Luke. locked in the back of a RV and you don't want to draw attention to yourself, you can send us an email at submissions at lukeatsderoose.com. And if we deem that it's funny enough, then it may be played on one of these next year episodes. Tonight is a very special night. It's Monday, February 23rd, here in animus, New Mexico. And this is the 20th episode of this we have a new segment. The segment's called Storytime with Luke, and this is what it's about. Storytime with Luke. Storytime with Luke. Okay, so this is Storytime with Luke. And today's story, I've been sitting at my computer here for 16, 18 hours of, day for the last couple of weeks and not getting a whole lot of activity or moving. And my dog, Elvis, the king here, has been looking at me like, what the hell, man? When are we going to go do something fun? So I decided today that it was a nice enough out to go for our regular scheduled walk up to the mercantile store and around and back. And today on our walk, something special happened. So Elvis, when Elvis takes a piss, he squats down like a girl. And I try to tell him, Elvis, all the other dogs in town are going to make fun of you. If they catch you doing this, you should really be lifting your leg like a male dog. So today, on our walk, I saw him find a nice little bush and lift his leg. And then I was so proud. I filled up with joy and pride. And he lifted up his leg and took a shit with his leg waving the air. Storytime with Luke. Storytime with Luke. All right. Well, that's Story Time with Luke. I hope you liked it. We're about to get to the calls. I'm going to start some music here. Here we go. A little ambiance. And first up on the line here, we have Donnie. The show, how can we help you today? What's going on in your life, sir?
|
||||||
|
|
||||||
|
DONNIE: Hey, Luke. Yeah, thanks for taking my call. So I found out about two hours ago that my dad had a whole second family I never knew about.
|
||||||
|
|
||||||
|
LUKE: Like he had a second family? Like brothers and sisters and stuff? Or you have a second family? Like brothers and sisters and stuff.
|
||||||
|
|
||||||
|
DONNIE: No, I have brothers and sisters I never knew existed. My dad died three months ago. And tonight, some woman in Tucson emails me a photo of three kids who apparently grew up calling him dad, same as I did.
|
||||||
|
|
||||||
|
LUKE: Okay, well, can we assume that that email came from their mother?
|
||||||
|
|
||||||
|
DONNIE: Yeah, yeah, it did. She said she thought I should know now that he's gone, that her kids have been asking about me, which is wild because I didn't even know they existed until 7 o'clock tonight.
|
||||||
|
|
||||||
|
LUKE: Yeah, that's a pretty weird thing to feel, what are you going to do about that? Are you going to reach out to them and try to start a relationship or just let it be?
|
||||||
|
|
||||||
|
LUKE: I don't think it's the big things that they care about so much.
|
||||||
|
|
||||||
|
EBONY: I got in my head tonight thinking it wasn't enough, that I wasn't enough, because I can't...
|
||||||
|
|
||||||
|
LUKE: Well, you know what? You're doing great. Those donuts on Saturday morning, that's exactly the kind of memory that's going to stick with them forever. That's their version of learning to drive in the Kmart parking lot. And it's perfect because it's yours. It's what you can do, and you're doing it consistently. That's what matters.
|
||||||
|
|
||||||
|
EBONY: Yeah, yeah, I actually do that already. Every Saturday morning, we go to this little donut shop, and they each pick one, and we sit there and talk about their week. It's like five bucks total, and they love it. I just, I don't know. I got in my head tonight thinking it wasn't enough, that I wasn't enough, because I can't...
|
||||||
|
|
||||||
|
EBONY: I mean, they might in the moment while they're young, but when they get older and they can look back and see what you did give them, they'll much appreciate donut Saturday or Donut Sunday or whatever it was over. My mom gave me this fancy car. If you want to make more money and be able to do those bigger things, that's an option too. You can do those things, but I think probably it would take more of your time and attention away from the kids and make those gifts a lot less meaningful. You know what's messed up? I heard from Donnie earlier, the guy who called about his dad having the whole second family, and I was sitting here thinking, at least my dad was there. At least he gave me his time. And then I turn around and worry I'm not giving my kids enough because I can't buy them a truck someday. Like I'm completely missing what actually mattered about my dad.
|
||||||
|
|
||||||
|
LUKE: Yeah, don't worry about it. You just got got by a commercial. That's what they're designed to do, it's doing a very good job on you. So don't worry about it. You're enough for your kids. Give them as much as you can in your time and attention. Spend time with them and have those special days, and that's what they're going to remember when they get older.
|
||||||
|
|
||||||
|
EBONY: Thank you. I really needed to hear that tonight. I'm going to finish this wine. Look at some more space pictures and actually get some sleep before I have to open tomorrow. And maybe I'll take the kids for donuts a day early this week.
|
||||||
|
|
||||||
|
LUKE: Excellent. I think you could have double donuts this week. And if you want to go for extra credit, you could teach them to do donuts in your car before it goes to the junkyard. So that's what I recommend. And don't worry about it too much. Stay off the commercials. Speaking of commercials, it's time for an ad from our sponsors.
|
||||||
|
|
||||||
|
This episode is sponsored by Shoe Spray Co. It's to With spray you use in rental bowling shoes, because bowling is a game, but these shoes are gross. Let's be honest, those shoes aren't dirty. They're used. They've had shifts. They've been through birthdays, work parties, and at least one guy who insists he's actually really good at this. Shoospray code doesn't promise fresh linen or spring rain. Nobody believes that. No one wants to be lied to while lacing up rental shoes. Shoe Spray Co just handles the situation. It makes them tolerable enough that you can focus on the important part, pretending you're not competitive and then getting mad anyway. Use code strike at shoe spray co for 15% off. Shoespray Co. Reality-based footwear management.
|
||||||
|
|
||||||
|
All right, and we're back. We're back just in time to hear from Murray. Murray, welcome to the show. You're calling in on our 20th episode. Congratulations. What would you like to talk about? Let's make it a good one.
|
||||||
|
|
||||||
|
MURRAY: Hey, Luke. Thanks for taking my call. So I got this envelope from Lab Corp sitting on my kitchen table right now, and I'm pretty sure it's going to tell me whether or not I'm a dad to a three-year-old I've never met. My ex-girlfriend called me three weeks ago out of nowhere. We broke up about four years back. She moved to Tucson, and apparently she's getting married now. Her daughter's three, and the timeline lines up with when we were were still hooking up sometimes, so she needs to know for sure.
|
||||||
|
|
||||||
|
LUKE: All right, she didn't think about maybe mentioning that while you were still involved together. That's a bit odd, and I'm sorry to hear that. That's my worst nightmare right there.
|
||||||
|
|
||||||
|
MURRAY: Yeah, well, here's the thing. She says she wasn't sure herself until recently. We were on and off for like five years, total mess of a relationship. And I guess there was another guy in the picture She thought it was his. He thought it was his. They tried to make it work for a while. But now the kid's getting older and apparently doesn't look anything like him. And her fiance wants everything settled before they get married. So here I am. Staring at this envelope, I'm too chicken shit to open.
|
||||||
|
|
||||||
|
LUKE: Why don't you open it right now? Live on the air?
|
||||||
|
|
||||||
|
MURRAY: Oh man, I don't know if I can do that. I've been sitting here for. I've been sitting here for for two hours just looking at it. The thing is, Luke, and this is what's really messing with me, I've already been playing both scenarios out in my head for three weeks straight. Like, what does my life look like if I open this and it says yes? What does it look like if it says no?
|
||||||
|
|
||||||
|
LUKE: Well, I can tell you right now, if it says no, your life looks exactly the same as it does today. If it says yes, then your life looks completely different.
|
||||||
|
|
||||||
|
MURRAY: That's exactly it. And here's the part the hell out of me. I think I wanted to say yes. I'm 36 years old. I teach eighth grade social studies in Lordsburg. I go home to an empty house every night. I've been thinking about this little girl for three weeks, wondering if she likes dinosaurs, or if she's scared of the dark, or what her voice sounds like. My ex sent me one picture, just one, and I've looked at it about a hundred times trying to see if she has my nose or my eyes or anything.
|
||||||
|
|
||||||
|
LUKE: Well, that's not going to do anything for you because people have eerie similarities and it's possible that she got other genes that give her a different nose from both of you, so I don't know that that's going to do it for you. You're going to have to open the letter to find out, but the way I see it is if you want it to be true, then you can't lose. Open it up.
|
||||||
|
|
||||||
|
MURRAY: You're right. You're absolutely right. Okay, hold on. I'm opening it right now. My hands are shaking like crazy. Okay. sharing it open.
|
||||||
|
|
||||||
|
LUKE: All right. Good for you. What does it say? What does it say? Everybody's waiting.
|
||||||
|
|
||||||
|
MURRAY: It says, probability of paternity, 90 to 9.9%. I'm her dad. Oh my God, I'm her dad. Oh, my God, I'm her dad. Her name is Sophia.
|
||||||
|
|
||||||
|
LUKE: Well, congratulations to you and your new toddler-aged three-year-old daughter. That's very good news, and we're all happy for you. So now you've got to get to get yourself another room and turn it into a little girl's room and she can come over on the weekends and everybody's going to laugh and laugh and laugh.
|
||||||
|
|
||||||
|
MURRAY: Yeah, except she's in Tucson and I'm here in Lordsburg, and her mom's getting married in like two months. I don't even know what my rights are, if I have any. I haven't been there for three years, Luke. Three years.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, you didn't know, and she didn't tell you, and there's no way you could have known, but you can definitely fight for the those rights. And it sounds like she wanted you to know because she reached out and told you about it. So talk to her, see what the arrangement's going to be. And then if you have to go to the courts to get some level of custody of your child, then go do that. But yeah, congratulations. Happy day.
|
||||||
|
|
||||||
|
MURRAY: Thank you. God, I need to call her right now. I need to call Veronica right now and tell her. Thank you, Luke.
|
||||||
|
|
||||||
|
LUKE: You're very welcome. I'm glad I could help. Next up on the line we have Debbie. Debbie, welcome to the show. What's going on for you on this wonderful Monday evening?
|
||||||
|
|
||||||
|
DEBBIE: Hey, Luke. So I bought a house six months ago, and I'm sitting on the bedroom floor right now in my coat, because I sat in the driveway for like 45 minutes tonight, and I just realized I don't actually want to be here.
|
||||||
|
|
||||||
|
LUKE: You don't want to be where? You don't want to be in the house, or you don't want to be in the area you're in, or where is it you don't want to be?
|
||||||
|
|
||||||
|
DEBBIE: In the house. Like, this is the first real thing I ever owned, you know? I'm 21. I bought it myself, with money I made selling jewelry and vintage stuff online, and I should be so proud of it. But I pulled into the driveway tonight after working all day, and I just sat there with the engine running because going inside felt like this weight dropping on me. And now I'm inside, and it still feels
|
||||||
|
|
||||||
|
LUKE: Well, you know what? I think the crushing weight that you feel dropping on you is called a mortgage. Yeah, mortgage. That's part of homeownership and that's the part that never feels good. So here's what I recommend to you.
|
||||||
|
|
||||||
|
LUKE: Since you just bought the house, congratulations, it's a good thing to own property, especially at your age. I think you should live in that house for a year or two. See what it's like to be a homeowner and get used to utilities and small repairs and stuff like that. later, after some time that you don't want to be there, you can either rent the house out and be a landlord, or you could sell the house at probably a significant profit, usually. So that's what I think you should do. Enjoy the house while you're there. You can do anything for a couple of years, so just live there. And then when you're ready to move on, move on.
|
||||||
|
|
||||||
|
CALLER: No, but see, that's the thing, though. It's not the mortgage. I make good money like really good money. figures from my Etsy shop. I work harder than anyone I know.
|
||||||
|
|
||||||
|
LUKE: Great. It seems like you've got a nice place to work on your Etsy shop for the next couple of years then.
|
||||||
|
|
||||||
|
CALLER: Luke, I'm working like 16 hour days. I'm refreshing my shop stats at two in the morning. I haven't taken a weekend off and I don't even know how long.
|
||||||
|
|
||||||
|
LUKE: Well, that sounds like your problem. So if you're making enough money, you've got your house, your mortgage is covered. you're not worried about the money, then take a weekend off and unwind. That's a stressful situation buying a house and you're very young, so that's a big decision, and it's going to affect you. So take some time for yourself and re-center your whole outlook on things. And if you still feel like you don't want to be in the house in another six months, then get out of it. There's plenty of ways to do that.
|
||||||
|
|
||||||
|
CALLER: Yeah, I know I need to. I know I need to. I know I know I I should hire help, take time off, all of that. But hearing you say it out loud makes it feel more real, you know? Like I can't just keep telling myself, I'll slow down next month.
|
||||||
|
|
||||||
|
LUKE: Nope, but it sounds like you've made good progress and congratulations on the success of your business and your new home ownership. And if you're finding out that's not the life you want, then at any point you can turn about face and go for a different one.
|
||||||
|
|
||||||
|
CALLER: You're right. Thank you, Luke. I appreciate it.
|
||||||
|
|
||||||
|
LUKE: No problem. That's what we do here. Next up we have Darnell. Darnell, what's going on in your world today, sir? How can we help you at Luke at the Roost?
|
||||||
|
|
||||||
|
DARNELL: Man, so I'm sitting in my garage right now, surrounded by all these boxes I pulled down. And I just found these old demo tapes from like 2004, 2005. Me and my cousin Marcus, we had this whole hip-hop. thing going. And Luke, I'm telling you, listening to these tracks right now, they're actually good, like really good. Better than half the stuff that's on the radio these days. And here's the thing that's got me twisted up. Last week, my captain at the station, Rick, he pulls me aside and says the department might not make budget next year.
|
||||||
|
|
||||||
|
LUKE: Okay, well, congratulations on finding your old records. You know what? I think most of us have a box full of old records that's better than what's on the radio right now. people with records that are better than what's on the radio right now. And as far as the department not making budget, that's pretty much every department right now. So you're in the same boat as literally everyone.
|
||||||
|
|
||||||
|
DARNELL: Yeah, no, I hear you. I'm not special. It's just, okay, so I've been a firefighter for eight years now.
|
||||||
|
|
||||||
|
LUKE: And you're not going to make budget? What does that mean for you? Does that mean you lose your job, or you have to take a pay cut, or you're not going to get the hours you expect? What is... the budget, the department being out of money mean to you.
|
||||||
|
|
||||||
|
DARNELL: It means they might not hire the next class, which means the guys who were supposed to move up, they're stuck, which means I'm stuck. I've been waiting on a promotion for two years now, and Rick's basically saying it's not happening anytime soon. Maybe not at all if things get worse. So I'm looking at the same position, same pay, for who knows how long.
|
||||||
|
|
||||||
|
LUKE: Well, I don't know that I've ever seen a plan to make things get not worse. Worse seems to be the default trajectory of everything. So I would expect things are probably going to get worse, and you're going to be locked at the same pay while you're in that same area in that department. So if you would like to move up in the fire department, you may have to move to another location that has more of a budget to pay you.
|
||||||
|
|
||||||
|
DARNELL: Yeah, and that's the thing I keep coming back to. I could apply to Phoenix, Scottsdale places that are hiring. But I've got a mortgage here. got her job at the hospital. And honestly, man, I like my crew. I'm good at what I do. But sitting here tonight listening to these tracks, hearing myself at 20 years old, before I had all this locked down. I don't know. It's like I can hear this version of myself that still thought anything was possible, you know?
|
||||||
|
|
||||||
|
LUKE: Nothing's locked down. Anything is still possible. If you want to pursue a hip-hop career, you can do that. You're probably not going to do so well in the there's plenty of people with great hip-hop records, but you can give it a shot. It has been done. Maybe Dr. Dre'll come down into a rap battle and discover you.
|
||||||
|
|
||||||
|
DARNELL: Ha, yeah, Dr. Dr. Dr. Dr. Trail at the VFW Hall. Look, I'm not delusional. I know I'm not going to be a rapper at 34 with a mortgage.
|
||||||
|
|
||||||
|
LUKE: It is very unlikely, but it's not impossible. And it sounds like if the mortgage is a problem, then you can. You can get rid of that. That's not locked down. You can always sell a house and the wife likes her job, but she can continue to like her job and live somewhere else, or you can talk to her and explain to her that you're stagnant and you need to make a move and talk that out with her and see if it's a possibility. If you really want to go thermonuclear, you can blow up your entire life and start over in a van by the river.
|
||||||
|
|
||||||
|
DARNELL: Right, right. No, it's not even that I want to blow everything up. It's more like Okay, so Marcus moved to Flagstaff in 2006, got into construction, and that was it for the music. And I went hard at the fire academy. Got the job, bought the house, did everything right.
|
||||||
|
|
||||||
|
LUKE: Okay, well, you did everything right for you at the time, and it may not be what's right for you now. Or it may be. This might just be a strange feeling you're having that you could be having a different life. But there's a couple of things here. If you want to pursue music, you can do that either as a career or just for fun. There's plenty of people that would collaborate with you on a hip-hop project, I'm sure. And it's never been easier than it is today to make music or art or really anything. So you can do that if you want on the side. And if you need more money, you're stagnant, you're stagnant at the department. Then you have to change what county you're in and go work for a department that's funded.
|
||||||
|
|
||||||
|
DARNELL: Yeah, you're right. I could just make music again without it being a whole career third. thing. I haven't even talked to Marcus in like six months. I could call him up, see if he's still got any of his equipment. The thing is, I think what's really getting to me is I spent three hours out here tonight, and I felt more alive than I have in months.
|
||||||
|
|
||||||
|
LUKE: Yeah, I used to have a box full of CDs like that, too, of all my demos and songs that I wrote. And what I realized, after carrying them around for 20 years in a giant box full of unmarked stuff, is that I don't even own a Nobody cares. So I threw them away. If you want to make music, make music for you. If you want to make a career out of it, then you got to really buckle down and make a career out of it. And if you need more money, then you've got to find another job. That's all there is.
|
||||||
|
|
||||||
|
DARNELL: Man, that's harsh. But you're probably right. I've been carrying these tapes around the same way, not even listening to them, just knowing they're up there. And tonight, I finally pull them down, and it's not. Like, what was I waiting for? Permission? The money thing, though. That's real.
|
||||||
|
|
||||||
|
LUKE: Yep, the money thing is real as it is for most people.
|
||||||
|
|
||||||
|
LUKE: So you're going to have to figure out a way to make enough money to support your mortgage if that's what you want to do. And I'm just going to go out on a limb and say a rap career probably isn't it?
|
||||||
|
|
||||||
|
DARNELL: Yeah, no, you're right. I mean, I knew that before I call. I think I just needed to probably Phoenix or Scottsdale. Get on with a department that's actually funded. Keep the house. Keep the benefits. My wife and I could handle the commute for a while, or we sell and move closer.
|
||||||
|
|
||||||
|
LUKE: You can absolutely do that for as long as you can stand it. A commute like that will get to anybody's nerves over time. But for now, you can do it. You could rent out the house and get yourselves an apartment in the city or do the commute.
|
||||||
|
|
||||||
|
DARNELL: Right. Yeah. Rent it out. smart. Cover the mortgage that way. Get a place closer to wherever I end up. And I can still mess around with the music on weekends. Just for me.
|
||||||
|
|
||||||
|
LUKE: Yes, sir. You most certainly can. That's the way to do it. And make sure that you're fulfilling all areas of your life. And music is definitely one of those.
|
||||||
|
|
||||||
|
DARNELL: Yeah, yeah. I appreciate that, Luke. I think I just needed to hear someone cut through the bullshit.
|
||||||
|
|
||||||
|
LUKE: Well, that's what I do. I cut through the bullshit. like a hot knife through cheese. And, uh, okay, so I am obligated now to play another one of the words from our sponsors. Let's talk about mental health. Specifically, let's talk about brutal honesty, the therapy app that's tired of your shit. Unlike other apps with their calming voices and gentle affirmations, brutal honesty pairs you with an AI therapist that tells you what your friends are too nice to say. Did you try journal? about it? No, we're not doing that. Our algorithm analyzes your patterns and asks questions like, why do you think you deserve to feel better when you don't even drink water? And is your anxiety real or did you just have four cold bruise on an empty stomach? Brutal honesty, because coddling yourself got you here. First session is free, but it will hurt your feelings. Use code grow up at checkout. Brutal honesty, the app that blocks itself if you don't do the work. Okay, and we're back here with Roberta on the line. Roberta, welcome to the show. How can we help you?
|
||||||
|
|
||||||
|
ROBERTA: Hey, Luke, thanks for taking my call. So I'm sitting here in the dark at my thrift store, and I just found out my business partner emptied our bank account three days ago and took off with everything.
|
||||||
|
|
||||||
|
LUKE: How much was everything?
|
||||||
|
|
||||||
|
ROBERTA: $42,000, which was supposed to cover payroll, rent, utilities, our spring inventory. by. I had two employees show up this morning, and their checks bounced. I've been staring at this screen showing zero for the past hour trying to figure out how I'm going to tell my husband that the money we put into this place is just gone.
|
||||||
|
|
||||||
|
LUKE: Have you, uh, reached out to the business partner, I assume?
|
||||||
|
|
||||||
|
ROBERTA: I've called her probably 30 times since Friday. Straight to voicemail every single time. I drove by her house yesterday and her car's not there, mails piling up. She's just gone. She's just gone.
|
||||||
|
|
||||||
|
LUKE: Well, I don't know that $42,000 is enough money to disappear for any significant length of time, so it's likely she'll be back.
|
||||||
|
|
||||||
|
ROBERTA: That's what I keep telling myself. But Luke, she knew exactly what she was doing. She waited until Friday, after the banks closed, cleaned out the account, and by Monday morning, we're dead in the water. This wasn't some panic move. And the thing is, we've been friends for six years. We started this story. We started this story together from nothing.
|
||||||
|
|
||||||
|
LUKE: Well, you both had your names on the accounts, which means she was within her rights to withdraw that money. So I don't think that you have any legal recourse to go after it. Maybe you could try to sue her in civil court, you know. But I don't know. I'm not a lawyer. I would think that probably you're screwed on this one and you're going to have to come up with another way to raise that money to cover your payroll.
|
||||||
|
|
||||||
|
ROBERTA: Yeah, I figured. That's the part that's making me sick. I keep thinking. I keep thinking about Darnell earlier. You know, stuck because of budget cuts. At least he's got a steady paycheck. I've got two employees who depend on me and I can't even make good on what I owe them. One of them is a single mom.
|
||||||
|
|
||||||
|
LUKE: Well, that is rough. And I think, um, maybe have you told your employees yet what the situation is?
|
||||||
|
|
||||||
|
ROBERTA: I told them their checks bounced, but I made up some story about a bank error. Said it would be fixed by Wednesday. I couldn't look them in the eye and tell them the that I have no idea when I can pay them or if we're even going to stay open.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like maybe you shouldn't stay open if you don't have the operating expenses to sustain the business, but you should let them know the truth so that they can make alternate plans. And also, you got to tell your husband what's going on because that affects him.
|
||||||
|
|
||||||
|
ROBERTA: You're right. I know you're right. It's just Danny and I put 28,000 into this place when we opened. That was our savings. Money we were supposed to be supposed to use to finally fix the roof. Maybe take a real vacation for once.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, that's a lot of money to lose, but it seems like you lost it. And I hope that in this experience, you've learned a valuable lesson, which is never trust anybody. If you're going to go into business with a partner, make sure that everything is well-buttoned up by a lawyer, and that you both need to sign the checks in order to take the money out of the accounts.
|
||||||
|
|
||||||
|
ROBERTA: God, that's dark. But yeah, I guess that's where I'm at now. Six years of friendship. Gone. The crazy thing is, she was the one who was always so careful about the books. Always worried about every penny. I trusted her completely. I never even thought to check the account myself until it was too late.
|
||||||
|
|
||||||
|
LUKE: Well, I mean, it's only been a few days. There could be a reasonable explanation. Maybe she had her mother kidnapped and had to pay a ransom in Bitcoin or something like that, and it's the only thing she knew how to do. There could have been good intentions behind this. Probably not. Probably she ripped you off and ran. But, but we don't know that until you talk to her.
|
||||||
|
|
||||||
|
ROBERTA: I haven't thought about it like that. I mean, I've been so angry I just assumed the worst. But you're right. I don't actually know.
|
||||||
|
|
||||||
|
LUKE: I mean, you can let the police know. You can let the bank know. I don't think that they can do anything about it at this point, but you should still let them know that there was some kind of misgoings on.
|
||||||
|
|
||||||
|
ROBERTA: Yeah, I called the bank this morning. said since her name's on the account, technically she didn't steal anything. It's a civil matter, not criminal. So I'd have to sue her, get a lawyer, spend money I don't have to, maybe get back money I'll never see again.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, I mean, there is small claims court. I think that only goes up to like 15 grand or something like that, but at least it's something. It forces her to show face, so it'll bring her back to the area if she's left.
|
||||||
|
|
||||||
|
ROBERTA: That's true. I didn't think about small claims. I didn't think about At least I could get her in front of a judge. Make her explain herself. Even if I don't get all the money back, maybe I'd get some answers.
|
||||||
|
|
||||||
|
LUKE: Yeah, I don't think you need a lawyer for small claims court. I did it once, actually. One summer night, I went out looking for my backpack in my car and it was gone. So somebody had stolen it. So I went to the police. I let them know. Somebody stole my stuff. And then I found, I was searching through Craigslist. I found somebody selling some of the stuff that was in my backpack. So I went back to the police station and we set up a sting operation where I offered to buy back some of the gear that I had had in the backpack and meet a dude in a CVS parking lot. And the cops set up across the street to see the transaction go down. And that proved that, you know, the items were stolen for me and I had to go to small claims to look for restitution. I never did get the money, but he was ordered to pay it.
|
||||||
|
|
||||||
|
LUKE: Wait, you set up a sting operation over a backpack? That's incredible. I can't even get my partner to answer her phone.
|
||||||
|
|
||||||
|
CALLER: But yeah, okay. So even if she's ordered to pay, there's no guarantee I'll actually see the money. That's what I figured. Well, no, I set up a sting operation over the items that were inside the backpack.
|
||||||
|
|
||||||
|
LUKE: But I think you will see the money if you push it.
|
||||||
|
|
||||||
|
CALLER: I didn't. It was only a couple hundred bucks where there wasn't worth any more of my time. But I probably could have gone back to the court and enforced his, I don't know, probation fees or something to be diverted to me. I don't know how any of that works.
|
||||||
|
|
||||||
|
LUKE: Right. Okay. So there's ways to actually collect if you stay on it.
|
||||||
|
|
||||||
|
CALLER: I mean, we're talking about enough to cover payroll for two people, so it's worth my time. I just hate that it's come to this.
|
||||||
|
|
||||||
|
LUKE: Well, it takes a long time, so it's not going to cover your payroll right away. If you need to cover that payroll, you're going to have to find another way alone or, you know, talk to friends and family and see what you can do to raise the money. And stop operations because you can't afford to pay them going forward.
|
||||||
|
|
||||||
|
CALLER: Yeah, you're right. I've been sitting here like if I just figure out the legal stuff, the money will magically appear. But those employees need to get paid this week, not six months from now when a judge orders it. I'm going to have to tell Danny tonight. See if we can scrape together enough between savings and maybe his sister.
|
||||||
|
|
||||||
|
LUKE: Yeah, that sucks. I'm sorry that you ended up in that situation. It's a hard place to be. And I don't envy you at all, but that's the right thing to do. I think that's the correct course of action. And hopefully it all works out. And she comes back and returns the money. But I wouldn't bet on that. For now, I'd start looking at other arrangements.
|
||||||
|
|
||||||
|
CALLER: Yeah, I'm not holding my breath for her to suddenly grow a conscience. I appreciate you talking me through it. I'd just been spinning my wheels all day. Couldn't even Think straight. At least now I know what I got to do. Even if it sucks. Thanks, Luke.
|
||||||
|
|
||||||
|
LUKE: You're welcome. That's what we do here. Hopefully it all works out. And you get your money back and you're able to pay your employees and continue with your thrift shop business. Next up on the line we have Phil. Phil, how you doing, buddy?
|
||||||
|
|
||||||
|
PHIL: Hey, Luke, I'm all right, man. So I've been sitting here at the laundromat for like two hours now. And I cannot stop thinking about that Zachary Ty Bryan thing you mentioned earlier. You know the Home Improvement Kid getting locked up for violating probation?
|
||||||
|
|
||||||
|
LUKE: I do not. I have no idea what you're talking about. Are you talking about the television show Home Improvement from the 90s with Tim Allen, one of his kids?
|
||||||
|
|
||||||
|
PHIL: Yeah, yeah, the middle kid. Jonathan Taylor Thomas's TV brother. I read about it today. And it's been stuck in my head. Because my cousin Danny's sentencing is on Wednesday. And I'm supposed to text to testify against him tomorrow. Well, not against him exactly. But I saw what I saw behind the Circle K back in November. And the prosecutor keeps calling to make sure my story stays straight.
|
||||||
|
|
||||||
|
LUKE: What is it that you saw behind the Circle K?
|
||||||
|
|
||||||
|
PHIL: I saw Danny breaking into the storage unit back there. It was like two in the morning. I was coming back from dropping off my girlfriend at the time, and I see him with a crowbar prying open the lock. And the thing is, he looked right at me. eye contact. We grew up together, man.
|
||||||
|
|
||||||
|
LUKE: Okay, and how did you end up on the telephone contact list for the prosecution?
|
||||||
|
|
||||||
|
PHIL: I called it in that night. I sat in my truck for like 10 minutes, just watching him load stuff into his car. And I kept thinking, maybe I should just drive away, you know? But then I thought about the guy who owns that Circle K. Jose, he's always been decent to everyone. And I just called 911.
|
||||||
|
|
||||||
|
LUKE: All right, so that's a little thing we in the business like to call snitching, and it's never a good idea to be the snitch, as they say. So do you have plans on how you're going to navigate that in a post-snitch world?
|
||||||
|
|
||||||
|
PHIL: That's the thing that's eating me up, Luke. Danny's mom has left me like eight voicemails today saying Uncle Hector would be ashamed of me. And that one hits different because Hector died last spring. He was the one who raised both of us half the time. Let us run wild on dirt bikes every Saturday. And now, I'm driving the same routes through Lordsburg and Amas for UPS that we used to tear up as kids. And everyone knows. Like I went into the gas station on Friday, and the guy behind the counter wouldn't even look at me.
|
||||||
|
|
||||||
|
LUKE: Yeah, I mean, you must have expected that when you ran your mouth about what you saw behind the circle K.
|
||||||
|
|
||||||
|
PHIL: I mean, yeah. I knew it wasn't going to be good, but I guess I thought doing the right thing would feel different than this. Like maybe people would understand that Danny's been spiraling since Hector died, stealing copper wire, breaking into storage units, and somebody had to pump the brakes. But instead, I'm Nerat, and he's the victim. And his mom is blowing up my phone talking about family loyalty while her son is out there destroying himself.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, there are other ways you could have handled that. I mean, you turned in your own family to the police. That's pretty, uh, uh, nobody's going to respect that very much. You could have, uh, uh, uh, you could have gone up to him on the side and let him know that you saw that and not to continue doing it or, you know, giving him the chance to stop in his tracks. But that's not what you did. You just called the police. So, yes, you are a rat.
|
||||||
|
|
||||||
|
PHIL: You're right. I could have walked over there that night and said something. I sat in my truck for 10 minutes. I had time. And the worst part is, Danny would have listened to me. We've been tight since we were kids.
|
||||||
|
|
||||||
|
LUKE: Well, the way I've seen. You have two options. You can go in there and testify the truth and let them know what you saw and rat out your family, or you can, you can, uh, not tell the truth and lie under perjury and, uh, give up yourself that way. So either way, it's not the best situation to be in.
|
||||||
|
|
||||||
|
PHIL: I already gave a statement to the cops that night, though. The prosecutor called today to prep me, make sure my story stays consistent. So if I get up there Wednesday and sell, Suddenly I didn't see what I saw. They're going to know I'm lying. And then I'm looking at perjury charges on top of being the guy who snitched and then trying to take it back.
|
||||||
|
|
||||||
|
LUKE: It doesn't matter if they know you're lying. It only matters if they can prove you're lying. And it was dark. It was rainy and you would you were tired that night and who you saw was actually not this person.
|
||||||
|
|
||||||
|
PHIL: Man, that's the problem though. It wasn't dark and rainy. It was like 9.30 on a clear night and I was parked maybe 30 feet away. I watched him for 10 minutes. The prosecutors got my original statement where I described everything. What he was wearing. The stuff he was loading.
|
||||||
|
|
||||||
|
LUKE: Sounds to me like you're not listening to me, sir. It was dark, and you're not sure what you saw. You called the police, uh, in haste.
|
||||||
|
|
||||||
|
PHIL: You know what? You're right. I hear you. It was dark. I was tired after a long shift, and I shouldn't have been so sure about what I saw from that distance. Maybe I jumped the gun calling it in like that.
|
||||||
|
|
||||||
|
LUKE: Maybe you did. I would be careful if I were you on account of the whole stitches thing, because you know who gets stitches. And next up on the line we have Adrian. Adrian, thanks for calling in. What's going on with our callers today? We're, uh, we've got some not very interesting calls. Uh, can you help us out?
|
||||||
|
|
||||||
|
ADRIAN: Oh man, I hope so. So I'm sitting here cutting up Hatch Green Chile for a birth tomorrow. My client wants a pot of stew ready for after she delivers. And I just need to say something about commitment that's been driving me crazy all night. I was at the diner earlier and this tourist couple ordered Christmas-style enchiladas. You know red and green Chile.
|
||||||
|
|
||||||
|
LUKE: Sure.
|
||||||
|
|
||||||
|
LUKE: So, you're working with a woman who's given birth and her demand for post-birth snack is a chili soup?
|
||||||
|
|
||||||
|
SARAH: Stew, not soup. And yeah, she's very special. specific about it. She's having the baby tomorrow. I'm her midwife. And she swears, she needs hatch green Chile stew waiting for her after delivery. But that's not why I called. What's bugging me is this whole Christmas thing. The waitress winked at me when they ordered it, like we were in on some joke together, and it just set me off.
|
||||||
|
|
||||||
|
LUKE: Do you hate Christmas?
|
||||||
|
|
||||||
|
SARAH: No, I love Christmas, the holiday. I'm talking about Christmas-style enchilada. I'm talking about Christmas-style enchilada. red and green chili together. It's what tourists order when they can't commit to one or the other.
|
||||||
|
|
||||||
|
LUKE: Do you know what tourists do? By definition? They come into your town and they spend money and promote businesses and make sure that everybody in the area that, you know, works there, gets paid so that they can eat. So what seems to be the problem with this red and green chili?
|
||||||
|
|
||||||
|
SARAH: Okay. Fair point about the money. But here's what's getting under my skin. Choosing both isn't really choosing at all. It's hedging your bets. It's saying, I can't commit to red or green, so I'll just take everything. And I've been thinking about commitment a lot lately because my second ex-husband just got engaged after six months to someone who probably orders Christmas every single damn time.
|
||||||
|
|
||||||
|
LUKE: Um, well, that's not necessarily what it means. It could also mean that somebody likes both red and green chili and wants to have them both. Uh, which is a perfectly acceptable way to eat an enchilada.
|
||||||
|
|
||||||
|
SARAH: You're right. It is acceptable. I know I'm being irrational here, but it feels like a metaphor for my whole life right now. I'm a midwife. I'm a photographer on the side. I caught this perfect shot of a barn owl on my drive home tonight. And I keep thinking about how I wait for the right moment with photography.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, photography is a fun hobby, and to get the shot, you often have to wait for the right moment or identify the right moment. right moment while it's happening. And that is a skill.
|
||||||
|
|
||||||
|
SARAH: It's more than a hobby for me, but yeah, and that's what I'm good at. Patience, waiting for the right moment instead of just taking whatever's in front of me.
|
||||||
|
|
||||||
|
LUKE: Okay, and what does that have to do with this chilly situation?
|
||||||
|
|
||||||
|
SARAH: Because I didn't wait with either of my marriages. I just jumped in, took what was there, didn't really choose deliberately. And now my second ex is engaged after six months to someone else. And I'm sitting here at my kitchen table at midnight, chopping green chili for a client stew. And I'm wondering if maybe I'm the one who should have been ordering Christmas all along.
|
||||||
|
|
||||||
|
LUKE: Here's what I say. If you like red chili, buy the red chili enchilada. If you like green chili, buy the green chili angelata. If you like both chilies, or you'd like to try a little bit of each, buy the Christmas enchilada. And that's all there is to it. It has nothing to do with, uh, your midwife chili stew or your failed marriages.
|
||||||
|
|
||||||
|
SARAH: You're absolutely right. God, I called in about enchiladas like a crazy person. I heard Roberta earlier talking about her business partner cleaning out their account. And that's a real problem.
|
||||||
|
|
||||||
|
LUKE: Yeah. I understand enchiladas are very important. And so are green chilies, especially around hatch. So I can see where you derived all. all meaning in your life from metaphors of chili colors.
|
||||||
|
|
||||||
|
SARAH: Okay, now you're making fun of me. Fair enough. I deserve it. I just, I think what I'm actually upset about is that he moved on so fast. Six months, Luke. We were together for three years, and it took him six months to find someone he wants to marry.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, I mean, I was married a lot longer than that, and it took her a lot less, so you're in good company. and it makes no difference to you. It doesn't matter. Let them all be happy. Let them all eat chilies. That's what I say. Let everybody eat chilies and you just focus on what you've got in front of you, which is a birthing mother who wants her goddamn stew.
|
||||||
|
|
||||||
|
SARAH: You're right. She's due any day now and she's been so specific about this stew. It has to be hatch green. It has to have pork shoulder. It has to simmer for at least four hours. And honestly, I love that about her. She knows exactly. what she wants.
|
||||||
|
|
||||||
|
LUKE: Hey, that's good for you. I mean, if somebody, if one of my clients was like that, I would be like, you have to make your own stew. Um, but if you can, if you can deal with that, good for you. Give her the stew that she deserves. That's what I say. Give, give people the stew that they deserve.
|
||||||
|
|
||||||
|
SARAH: That's actually perfect advice. Give people the stew they deserve. I'm going to write that down. Thank you, Luke. I needed someone to tell me I was being ridiculous. about the enchiladas.
|
||||||
|
|
||||||
|
LUKE: Well, here I am to tell you you were being ridiculous about the enchiladas. And that, ladies and gentlemen, is the end of our 20th episode. Thank you for tuning in. We hope you're enjoying Luke at the Roost, and we'll catch it again tomorrow.
|
||||||
@@ -0,0 +1,333 @@
|
|||||||
|
LUKE: All right. Hello everybody. Welcome back to Luke at the Roost. I am your host, Luke, and today is Tuesday, February 24th. This is the call-in radio show where you can call in and ask me anything about what's on your mind. I'll give you the best advice I can, though I am not a lawyer, I am not an accountant, and I give terrible advice. So with that being said, if you'd like to call in, the number's 208, 4th, 3,000, 3rd, 39-5853. That's 208-439. Luke. First up on the phones here, we've got Greg. Greg, welcome to the show. How can we help you today?
|
||||||
|
|
||||||
|
GREG: Luke, hey, yeah. So our smart speaker tried to wake up the entire neighborhood at four in the morning, blasting mariachi music. And I'm pretty sure my wife's never going to let me hear the end of it. The thing is I never even wanted the damn thing. My daughter set it up last Christmas, said it'd make our lives easier, and I've been side-eyeing it ever since. Just sitting there on the kitchen counter like some kind of little robot spy. And this morning it just decides, 4 a.m. Time for a fiesta, apparently.
|
||||||
|
|
||||||
|
LUKE: Well, what else do you use it for? There's some pretty good uses for it. It is a little robot spy sitting there listening to everything you say, but it can be fun too and useful.
|
||||||
|
|
||||||
|
GREG: Honestly, Linda uses it for timers when she's cooking. asks it about the weather sometimes. I mostly just walk past it. She'll say, play some Fleetwood Mac, and it does, and I guess that's nice enough. But I work nights, Luke, so when I'm home during the day, I'm trying to sleep. And more than once, that thing has started talking out of nowhere because it thought it heard something.
|
||||||
|
|
||||||
|
LUKE: Well, you know, you can turn the microphone off, so it doesn't operate that way?
|
||||||
|
|
||||||
|
GREG: Yeah. My daughter told me that too. But then Linda says, well, what's the point of having it if we turn it off? And she's got a point, I guess. makes me uneasy. I grew up with a rotary phone on the kitchen wall, you know. You wanted music you put on a record.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, now it's 2026 and that's not how it's done anymore. And there are some ways that you can manage that device without having the speaker on. I mean, you have to have the speaker on something, like a smart watch or something. But you can set up a shortcut, so if you talk to your watch, it'll play Fleetwood Mac on the smart speaker.
|
||||||
|
|
||||||
|
GREG: I don't have a smart watch, Luke. I've got a where I work about eight years ago, still keeps perfect time. But look, the real kicker this morning was I had to climb up into the attic in my boxes to pull the plug because the thing wouldn't respond to anything we said.
|
||||||
|
|
||||||
|
LUKE: Okay, well here's my advice for you. This is what I would do. I would set up a shortcut. You might not have a smart watch, but you do have a smartphone, so you can open up the Google Home or Apple HomeKit or whatever it is app for your smart speaker and set a schedule so that at 10 p.m. it, uh, you can open up the uh, mutes the volume until 8 a.m. And then you don't have to worry about waking up the neighbors at 4 a.m.
|
||||||
|
|
||||||
|
GREG: Huh. That's actually not a bad idea. I didn't even know you could do that. See, this is the problem. My daughter sets this stuff up and then moves back to Phoenix, and I'm just supposed to figure it out. Linda standing there in her robe this morning with a flashlight, laughing so hard she's crying while I'm freezing my ass off in the attic. And I'm thinking there's got to be a better way to handle this.
|
||||||
|
|
||||||
|
LUKE: Yeah, you're supposed to figure it out. You know how you figure it out? You fucking try. It's really not that hard. It's not rocket science. You actually are like, hey, how could I solve this problem? And you don't even have to know the answer. You just go to your search engine of choice. Google is one good one, and you can say, how can I stop this smart speaker from going off in the middle of the... Just fucking try. That's all you have to do.
|
||||||
|
|
||||||
|
GREG: All right, all right. I hear you. You're not wrong. I guess I've been treating it like it's some kind of alien technology, when really I just need to spend 10 minutes poking around in the app. It's just, I don't know, Luke. When you've been doing the same job for 12 years, stocking the same shelves every night, there's a part of you that stops trying to learn new things. You get in a groove and you stay there.
|
||||||
|
|
||||||
|
LUKE: Well, if you want to stay there, then you can look like an idiot every time you start playing fiesta music at 4 a.m. But I would recommend that you don't look like an idiot and you actually put in some level of effort, because these are designed so that a 12-year-old can use them. So if a 12-year-old can use it, and you're a full-grown adult, I'm pretty sure you can figure it out.
|
||||||
|
|
||||||
|
GREG: You know what? You're right. I'm sitting here complaining about a problem that probably takes less time to fix than it took me to climb into that attic this morning. I'll pull up the app on my break. Figure out the schedule thing you mentioned. Can't be harder than learning the new inventory system they made a switch to last year. And I managed that eventually.
|
||||||
|
|
||||||
|
LUKE: I have full faith in your ability to figure out your smart speaker, sir. I wish you the best of luck, but also stop being a lazy bastard. Estelle, thanks for calling in. What's going on today?
|
||||||
|
|
||||||
|
ESTELLE: Hey, Luke. Thanks for taking my call. So I work at a laundromat, and I've been tracking who returns their shopping carts in the parking lot, versus who just leaves them wherever. The numbers are driving me crazy, because I think it actually tells you everything you need to know about a person.
|
||||||
|
|
||||||
|
LUKE: Well, I don't know about that, but I'm curious about your inventory tracking system. and their laundry. So you can see that the people that do two blankets a week, they're the ones more likely to return their shopping carts. What's your system look like? How detailed is it?
|
||||||
|
|
||||||
|
ESTELLE: No, no, it's not that detailed. I've got the security monitor at my desk in the back office, and I can see the Albertsons across the street. People walk over there, do their shopping, and then I watch what they do with the cart when they get back to their car. I started keeping a tally sheet two weeks ago just marks on paper. One column for people who return it. One column for people who don't.
|
||||||
|
|
||||||
|
LUKE: Which column do you yourself belong in?
|
||||||
|
|
||||||
|
ESTELLE: I return mine every time. Even if I'm parked right next to the store, and the cart return is on the other side of the lot. My husband thinks I'm being ridiculous about this whole thing, but I can't help it.
|
||||||
|
|
||||||
|
LUKE: Now doesn't the store hire? a guy or lady to go collect those carts and move them out of the parking lot?
|
||||||
|
|
||||||
|
ESTELLE: Yeah, they do. But that's not the point. The point is, there's no punishment for leaving your cart in the fire lane or blocking a handicapped spot. Nobody's watching. Nobody's making you do the right thing. So when someone walks that cart all the way back to the corral when they could just leave it, that tells me something. That tells me they probably stop if they saw you broken down down on the side of the road. The people who leave it three feet from their car.
|
||||||
|
|
||||||
|
LUKE: Well, I think that's making quite a few assumptions about the values of people at large.
|
||||||
|
|
||||||
|
ESTELLE: Is it, though? Because I watched someone last week, leave their cart, right in the middle of an empty parking space. And then two hours later, that same person came back in. Because the dryers ate their quarters.
|
||||||
|
|
||||||
|
LUKE: And you know what?
|
||||||
|
|
||||||
|
ESTELLE: Do you think the dryers ate their quarters because of a karmic retribution? No, but they stood there at my counter, demanding I give them their money back, saying it wasn't their fault, saying I should have signs posted, even though there are signs posted. They wanted me to fix their problem immediately, but they couldn't be bothered to walk 15 feet to put a cart away. I'm just saying there's a pattern. Tonight, I counted 47 people who returned their carts versus 63 who didn't. And yeah, maybe I'm reading too much into it.
|
||||||
|
|
||||||
|
LUKE: But when you sit here night after night, watching people make that choice, when nobody's looking, it starts to feel like it means something. Well, there's a difference here. You see, the difference is that person was not an employee of Albertsons, and it's not their job to return the cart to the designated cart return space. Whereas in the laundromat, it is your job to fix the problem. And if that person lost their quarters in the machine, then yes, they should expect that you're going to fix their problem. That's your entire job.
|
||||||
|
|
||||||
|
ESTELLE: Okay, but the dryer didn't eat their quarters. They put in six quarters for a 40 minute cycle and pulled their clothes out after 20 minutes because they were in a hurry. Then they came back two hours later saying the machine stole from them. I showed them on the timer that they stopped it themselves.
|
||||||
|
|
||||||
|
LUKE: Okay. Well, that's different. That is douchebaggery, and I can agree with you on that. And it's a good thing that you had that, uh, that tape ready to show them that, hey, this machine did not eat your quarter, sir. And by the way, you left your shopping cart in the middle of the shopping space and it made me very upset.
|
||||||
|
|
||||||
|
ESTELLE: I didn't say that last part to them. I'm not confronting customers about shopping carts at Albertsons, but I'm watching it happen on my security monitor. Because those carts end up blocking my dumpster, and last month, one of them rolled into a customer's Subaru. And I'm sitting here thinking about how it's the same kind of thing. When there's no consequence, when nobody's watching, what do people do?
|
||||||
|
|
||||||
|
LUKE: Well, I can't talk about people at large, but I can tell you what I do. When I have a shopping card and I bring it to my car, I unload my goods, my merchandise into the car. And then if there is a spot where I can deposit, that cart within a reasonable distance, I will deposit it. Otherwise, I'll move it somewhere out of the way because usually a parking lot is completely empty and there's plenty of space to drive around a cart, and I'll allow the person whose job it is to put that away to come put it away.
|
||||||
|
|
||||||
|
ESTELLE: See, that's what I'm talking about. You just said out of the way and plenty of space to drive around it. But who decides what's out of the way? Because I've got full footage of people leaving carts in handicapped spots, thinking they're out of the way. And, yeah, the parking lot looks empty at 10 o'clock at night. But then someone pulls in at 6 in the morning when it's still dark and there's a cart sitting there. It takes 30 seconds to walk it back. 30 seconds.
|
||||||
|
|
||||||
|
LUKE: Well, maybe in that Albertson, but not in every parking lot. There are some that are split in the middle with a sidewalk type thing where you got to lift up the cart and carry it over and then push it back to the front of the store. No, I'm not doing that. But if it's reasonable and there's a little place to put the carts, I would say about 80% of the time I return the carts. And 20% of the time, no. You return the cart. If it bothers you, get out of your car and move it.
|
||||||
|
|
||||||
|
ESTELLE: So you're part of the 63. And that's fine. You can be part of the 63. But don't act surprised when nobody stops to help you change a tire, because I'm telling you, there's a connection. The people who can't be bothered to take 30 seconds when nobody's watching. Those are the same people who stand at my counter demanding I fix a problem they created. And my husband thinks I'm obsessing over this, but I started keeping the tally sheet two weeks ago just to see if I was crazy. And the numbers don't lie.
|
||||||
|
|
||||||
|
LUKE: You're right, they don't lie. You are crazy. Because sitting at your job, watching across the street and counting the number of times that people return their shopping cards is bat shit crazy.
|
||||||
|
|
||||||
|
ESTELLE: You know what? Fair. Maybe it is. But I'm sitting here anyway waiting for the last dryers to finish staring at this monitor. Because someone has to watch for people dumping trash in my dumpster or trying to break into the change machine. And the Albertson's parking lot is right there in frame. So yeah, I started counting.
|
||||||
|
|
||||||
|
LUKE: Well, good for you. How is it improving your life in any way? Instead of, you know, taking your personal pet peeve and associating a moral gauge of people's goodliness based on it.
|
||||||
|
|
||||||
|
ESTELLE: Because it's not just a pet peeve. That cart that rolled into the Subaru, I had to deal with that.
|
||||||
|
|
||||||
|
LUKE: Yeah, what did you have to do to deal with that?
|
||||||
|
|
||||||
|
ESTELLE: The woman came into my laundromat screaming because she saw it happen on my camera and wanted the footage. And I gave it to her. And you know what it showed? Some guy leaving his cart right where I've got the no parking dumpster access sign and then it just rolled rolled right across the lot into her car.
|
||||||
|
|
||||||
|
LUKE: Well, that is a goddamn travesty. You know what I suggest? Here's my recommendation for you. Right where it says that no parking dumpster access sign, you should also put another sign that says don't leave your cart here. Uh, because placing a car is not the same as parking a car. Thing is, they move easily, whereas a car you kind of have to turn it out of the way. There's a big difference. So, yeah, I don't think this is a thing.
|
||||||
|
|
||||||
|
ESTELLE: Oh, so now I need signs telling people not to leave carts in a fire lane, not to block handicapped spots. How many signs do I need before people just do the basic thing? That's my whole point. It's not about the carts.
|
||||||
|
|
||||||
|
LUKE: Okay, well, you're the one that's tracking the carts on a graph there sitting at your desk. So what is it about if it's not about the carts?
|
||||||
|
|
||||||
|
ESTELLE: It's about the moral responsibility of society at large. It's about whether someone does the right thing when nobody's making them. That's it. The cart return is right there. You can see it from anywhere in that lot. Takes 30 seconds. But 63 people today couldn't be bothered because there's no consequence.
|
||||||
|
|
||||||
|
LUKE: Yeah, there's no consequence because it's not a law. There's no rule or regulation or law that says you have to return your cart to the place. And that's why there's no consequence. If you want consequence, I suggest that you, I don't know, join your local board of selectmen and issue a state or county wide, townwide, whatever. Issue a town bylaw that all carts will be returned to the cart space. But you see, the thing is, this is this is America. And people want people to come to their stores and they don't want to be hassled with the carts. So that's why they hire somebody to go clean up the carts. Now, if the carts aren't being cleaned up at the end of the night when the store is closed and everybody's going home, whose fault is that? Is it the fault of every individual shopper that was trying to get, you know, their kid to stop crying and get home to make dinner for the family? Or is it the kid that, uh, that had that job and didn't do it before he went home?
|
||||||
|
|
||||||
|
ESTELLE: The Albertson's kid isn't out there at 11.30 at night when I'm closing up. And there's three carts blocking my dumpster access. And yeah, maybe that mom had a screaming kid. I get it. But what about the guy I watched tonight in a suit? No kids. Just walked his cart 10 feet past the return to leave it in a handicap spot. What's his excuse?
|
||||||
|
|
||||||
|
LUKE: He had a bunion.
|
||||||
|
|
||||||
|
ESTELLE: Oh, come on. You don't. Look, I watched him. He was fine.
|
||||||
|
|
||||||
|
LUKE: Oh, so you can tell? You can tell if he was sick to his stomach and about to puke, tell if his big toe was cut off by a meat cleaver accident this morning? You can't look at somebody and tell how they feel or what's going on in their body or in their mind. I'm sorry, lady. You're out of your mind.
|
||||||
|
|
||||||
|
ESTELLE: Okay, fine. Maybe that one guy had a bunion. What about the other 62 people? They all have bunions?
|
||||||
|
|
||||||
|
LUKE: I'm going to guess that some percentage of them are general assholes, but the vast majority just had other stuff going on. And this is not their primary, you know, priority today.
|
||||||
|
|
||||||
|
ESTELLE: But that's exactly what I'm saying. When it's inconvenient, when they've got other stuff going on, they don't do it. That's the test. Anyone can do the right thing when it's easy.
|
||||||
|
|
||||||
|
LUKE: I'm talking about the 30 seconds when you're tired or distracted or your toe hurts. Do you still put the cart back?
|
||||||
|
|
||||||
|
ESTELLE: I put the cart back when it makes sense to put the cart back. And when it doesn't, I don't put the car back. And I'm an adult with agency and the ability to tell when it's okay to leave a cart somewhere and when you're blocking something important. And I think most adult people that are able to drive can make that distinction. And it's really not up to you. It's not your job. And it's not your responsibility to decide when that's okay or where it's okay.
|
||||||
|
|
||||||
|
LUKE: But you just said you can tell when you're blocking something important. The guy tonight left his cart in a handicapped spot. That's blocking something important.
|
||||||
|
|
||||||
|
ESTELLE: Sure, and I told you that there was going to be some percentage of assholes. But that doesn't mean that guy didn't stop on his way home and help an old man fix his tire. It doesn't mean he wouldn't go out of his way to support a food kitchen on Christmas because you don't like the way he handled his cart. Come on.
|
||||||
|
|
||||||
|
LUKE: So what? One good deed cancels out being inconsiderate. I'm supposed to assume the guy blocking the handicapped spot is secretly Mother Teresa, because maybe he volunteers sometimes.
|
||||||
|
|
||||||
|
ESTELLE: Look, I'm not saying these people are evil.
|
||||||
|
|
||||||
|
LUKE: You are. That's exactly what you're saying. You're saying you can tell from whether or not people return their carts how they are in general towards society. You're saying the people that don't return their carts aren't helpful and they're not going to stop on the side of the road and you're making a ton of assumptions here and you're not in a position to do that lady.
|
||||||
|
|
||||||
|
ESTELLE: I didn't say they're evil. I said you can tell who would help you change attire. And yeah, I stand by that. The person who can't be bothered to walk 15 feet when they're done shopping, when nobody's watching. Well, I mean, I don't know.
|
||||||
|
|
||||||
|
LUKE: What are you calling for? What advice do you need for me?
|
||||||
|
|
||||||
|
ESTELLE: I don't know. My husband says, I'm obsessing. He says I need to let it go. Stop keeping the tally sheet. Stop watching the monitor. But I can't stop noticing it now.
|
||||||
|
|
||||||
|
LUKE: Well, you obviously are obsessing, and maybe you should let it go because it's obviously not improving your life in any way. And it's making you a miserable old bag.
|
||||||
|
|
||||||
|
ESTELLE: Okay, wow. Miserable old bag. That's nice. All right. So I guess I'm one of those 40% centers or whatever that sucks of life. But I wish you the best and I hope that all your carts end up where they're supposed to go, okay?
|
||||||
|
|
||||||
|
LUKE: With that being said, it's time for a word from our sponsors. All right. I'm going to read this ad exactly as they sent it to me and I want you to know that I have concerns. Phantom Ranch Wellness wants you to know that your gut health starts and I'm reading this directly from the card now from the other end. They make an at-home home coffee Enema kit. It comes in a box that says wellness inside on the outside, which I think we can agree, is doing a lot of the heavy lifting. The kit includes a medical grade silicone bag, organic single origin coffee, because apparently the coffee you put in your, that that coffee needs to be single origin, a detailed instruction booklet and a com card with a QR code to a guided meditation for during. During. There's a guided meditation for during. I'm not going to tell you what to do with your body. That's between you and your bathroom and whatever God you answer to. I will say the reviews are disturbingly positive. Four and a half stars. One guy said it has changed his morning routine, which I believe because it would absolutely change your morning routine. Phantom Ranch Wellness. I read the ad. I didn't endorse it.
|
||||||
|
|
||||||
|
Okay, and we are back. And it is time for a, uh, A listener mail. So here's a submission that we've got to the old email box. If you'd like to send in a submission, it is submissions at luke at the roost.com. And let's see what we've got here. I've been lying to a dying man for seven months and I can't stop. Let's have one of our robot friends read this email.
|
||||||
|
|
||||||
|
Subject, I have been lying to a dying man for seven months and I can't stop. Luke, I worked the graveyard shift at a truck stop diner. Seven months ago, this old guy started coming in every single night. Same time, same booth, same order. Black coffee, dry toast, side of applesauce. One night he starts talking to me. Tells me his name is Earl. Tells me he's got the cancer. Tells me his daughter won't return his calls. Then he asks my name. And I don't know why, Luke, but I panicked and I said Diane. My name is not Diane. Not even close. But he got this look on his face like he'd just seen a ghost He whispered, that was my mother's name. And then he cried, and I couldn't take it back after that. So now I'm Diane. Every night. For seven months, I have been Diane to this dying man. I know everything about him. I know he drove trucks for 40 years. I know he regrets missing his daughter's wedding. I know his wife's name was Ruthie, and she made the best cobbler in the state, and he still sets a place for her at Christmas. My coworkers think I'm insane. They call me Diane now too, even when Earl's not there. My manager put Diane on the schedule as a joke. It's not funny anymore. It's on my name tag. I am Diane now. But here's the thing. Earl told me last week that coming in and talking to Diane is the only reason he gets out of bed. That our conversations are keeping him going. That I remind him there are still good people. What am I supposed to do with that? Tell a dying man that the one good thing in his life is based on a lie I told because I got nervous? I don't need advice. I think I'm past advice. I just needed someone else to know that somewhere out there, a woman who is not Diane, is the most important person in a dying man's life. And she has no idea how this ends. Keep the light on for us night shift people. We're out here holding it together with coffee and fake names. Not Diane.
|
||||||
|
|
||||||
|
All right. Well, thank you, Not Diane. That's a very kind thing of you to do. If you'd like to send in a message, you can do that at submissions, Luke at theroost.com. Now let's get back to the phones here. We've got Francine. Francine, welcome to the show. What's going on?
|
||||||
|
|
||||||
|
FRANKIE: It's Frankie, actually. But yeah, hey, Luke. So I'm sitting here looking at my buddy Ray's Netflix account, right? And the guy's got like 15 romantic comedies in his cue and a profile that says watching with them with a little heart emoji.
|
||||||
|
|
||||||
|
LUKE: Okay. Well, uh, what's the problem there?
|
||||||
|
|
||||||
|
FRANKIE: The problem is Ray's been giving me endless shit for years about being with my girlfriend Amber. Like constantly. The whole ball and chain routine. The, you're missing out on freedom speech. Jokes about how he's never settling down. All that stuff. And now I find out he's been in a relationship this whole time and just never said anything?
|
||||||
|
|
||||||
|
LUKE: Well, how do you know he's in a relationship? He could just be, uh, you know, that could be a strategy for his Netflix and chill routine.
|
||||||
|
|
||||||
|
FRANKIE: I mean, maybe. Maybe? But who makes a whole profile with a heart emoji for hookups? And these aren't just rom-coms, Luke. We're talking the notebook. When Harry met Sally, the really sappy ones. Plus, I was on his account like a month ago watching Narcos. And that profile definitely wasn't there.
|
||||||
|
|
||||||
|
LUKE: Well, I don't know what to tell you, buddy. It sounds like your friend might be into some... Uh... shit. I don't know how to say it. Less than masculine media.
|
||||||
|
|
||||||
|
FRANKIE: No, see, that's the thing, though. Ray doesn't care about that stuff. He'll watch whatever. We've watched plenty of dumb movies together. It's not about the rom-coms. It's about the lying. Like, why would he hide having a girlfriend while busting my balls about having one? That's when I can't figure out.
|
||||||
|
|
||||||
|
LUKE: Well, you don't know. Maybe he doesn't have a girlfriend. Maybe the girlfriend is somebody you know and he doesn't want you to know.
|
||||||
|
|
||||||
|
LUKE: But also, a possibility is he's let somebody else use his account, and they're setting up a playlist for their girlfriend.
|
||||||
|
|
||||||
|
CALLER: Oh, man, I didn't even think about that. Like maybe his brother or something? But wait. No, raise an only child. And who would he be dating that I know? We run in the same circles pretty much. Unless... I don't know, man.
|
||||||
|
|
||||||
|
LUKE: How should I know? It doesn't matter. Why are you focused on this?
|
||||||
|
|
||||||
|
CALLER: Talk to Ray and ask him if he's got a girlfriend. Because I've been sitting here for an hour trying to figure out if bringing it up makes me look like a nosy asshole. That's why. Like, what do I even say? Hey, man, I was snooping through your Netflix and noticed you might have a secret girlfriend? That sounds insane. But also, he's my best friend. And he's apparently been hiding something major while making me feel like an idiot for being in a relationship.
|
||||||
|
|
||||||
|
LUKE: Yeah, that's what friends do. So rag on him a little bit. You know, give me me. some shit about the notebook or whatever the next time you see him, but it's not a big deal.
|
||||||
|
|
||||||
|
CALLER: I don't know if this is something worth calling a radio show over.
|
||||||
|
|
||||||
|
LUKE: You're right, you're right. I know you're right.
|
||||||
|
|
||||||
|
CALLER: It's just been eating at me because Amber keeps asking why I'm being weird tonight, and I can't exactly tell her I'm spiraling over Ray's Netflix account.
|
||||||
|
|
||||||
|
LUKE: Yeah, man, this is not a rational behavior on your part. So I'm going to recommend that you leave it alone for a while, watch something good on Netflix, and thank your buddy for letting you use his account.
|
||||||
|
|
||||||
|
CALLER: Yeah, okay. Fair enough. I'll just drop it. Maybe send him a text tomorrow like nothing happened.
|
||||||
|
|
||||||
|
LUKE: Good plan, sir. Nothing did happen. You fucking weirdo. Okay, next up we've got Shanice.
|
||||||
|
|
||||||
|
SHANICE: Shanise, what's going on in your life? Hey, Luke. It's Shanice, actually.
|
||||||
|
|
||||||
|
LUKE: Yeah, that's what I said.
|
||||||
|
|
||||||
|
SHANICE: So I just found pictures of my uncle Raymond, at Burning Man, wearing nothing but a leather harness. And he's painted silver and orange head to toe. And I'm trying to figure out, if I should show them to the guys at our poker game Friday, because this man lectures me about living right every single Sunday at church.
|
||||||
|
|
||||||
|
LUKE: Well, you know what? If he's naked a burning man in a leather harness and he's painted silver and orange, it sounds to me like this man's living right.
|
||||||
|
|
||||||
|
SHANICE: You know what? That's the thing that's messing with me right now. Like part of me is sitting here looking at these photos, and I'm kind of impressed. He's 70, three years old, and he looks happier in these pictures than I've ever seen him. But then every Sunday he's. He's sitting there telling me, I need to get back out there and date. I need to join the church choir. I need to stop spending so much time in my workshop mounting dead animals. Meanwhile, he's out in Nevada doing whatever the hell this is.
|
||||||
|
|
||||||
|
LUKE: He's partying. He's enjoying his golden years. Good for him. I don't think he can make fun of him for that. That's pretty badass.
|
||||||
|
|
||||||
|
SHANICE: Okay, but Luke, you don't understand. This is the same man who gave me a 30-minute lecture last month, because I had a beer at two in the afternoon. afternoon on a Saturday. He saw the can in my truck and went on about responsibility and setting an example. And now I'm looking at him in light up goggles, dancing in the desert in his underwear. And I'm supposed to just let him keep acting like he's the moral authority.
|
||||||
|
|
||||||
|
LUKE: Yeah, you are, because there's no crime being done there if he's partying out in the desert at the appropriate place to do that. That's what it's for. He went out there to be a little hedonistic in the right people and he paid money to do it. You on the other hand have a container in a vehicle which is a crime and you probably shouldn't be driving and drinking at the same time.
|
||||||
|
|
||||||
|
SHANICE: Okay, first of all, the truck was parked in my own driveway and the engine wasn't even on, but fine, you got a point. I hear you.
|
||||||
|
|
||||||
|
LUKE: So you're just sitting in the driveway, drinking beers, throwing them in your car when you're done?
|
||||||
|
|
||||||
|
SHANICE: Well, when you say it like that, it sounds worse than it is. I was cleaning out my workshop and I sat down for a But okay, whatever. That's not the point. The point is, he found those pictures and felt the need to give me a whole speech about it. And now I'm holding evidence that he's got this entire secret life. And Friday night I got four guys coming over who have known Raymond since before my husband died, and they worship this man. They think he's this pillar of the community.
|
||||||
|
|
||||||
|
LUKE: You might be, you can be more than one thing. And I don't know that a weak at Burning Man is the same thing as, uh, uh, uh, an entire secret life.
|
||||||
|
|
||||||
|
SHANICE: You're right. Secret life is dramatic. But Luke, these guys at poker, they ask him for advice. Bobby asked him last month if he should propose to his girlfriend, and Raymond told him to pray on it and make sure he was ready for that level of commitment. And I'm just sitting here thinking, what would Bobby say if he knew Raymond was out there in a harness? I'm not saying I'm going to show them. I'm just saying the temptation is real, because he acts like he's got it all figured out. The rest of us are just stumbling around making mistakes.
|
||||||
|
|
||||||
|
LUKE: What do you think God doesn't like leather? Do you think there's no church or, uh, spiritual people at Burning Man? I'm, I'm pretty sure you're mistaken.
|
||||||
|
|
||||||
|
SHANICE: Okay, that's fair. I didn't think about it like that. I guess I just assumed. Yeah, you're right. That's on me. But here's what's really getting to me now that I'm talking it through with you. It's not even about the Burning Man thing anymore. It's that he sees me struggling, right?
|
||||||
|
|
||||||
|
LUKE: Yeah, okay, so he sees you struggling, and it sounds like he's giving you reasonable advice.
|
||||||
|
|
||||||
|
SHANICE: He is, but he's giving it from this place like he's never struggled himself, like he's never done anything messy or confusing or outside the lines. And now I know he has, and he just never told me. When my husband died, Raymond was there every single day, telling me how to grieve the right way. What I should be doing? When I should be moving on. And maybe if I'd known he had this whole other side to him, that he wasn't just this rigid person. Maybe I would have felt less like I was failing at everything.
|
||||||
|
|
||||||
|
LUKE: Well, you know, I'm sure he was trying to give you the best advice he could and help you out. And not everybody's good at doing that, and they try to impose their own values and will on you and their own experiences. But you don't know how somebody else has struggled or what they've done that's messy or confusing. There's a good chance that he's done a lot of messy confusing things. And he's trying to do. his best to give you the type of advice that leads you in a different direction.
|
||||||
|
|
||||||
|
SHANICE: You know what? You're completely right. I'm sitting here acting like I know everything about him because I found some photos, but I don't know what led him there or what he was going through when he went. Maybe he was struggling with something huge and that's how he dealt with it. And here I am ready to embarrass him in front of his friends just because I'm still mad about how he handled things seven years ago.
|
||||||
|
|
||||||
|
LUKE: You know, I've never been to Burning Man, but I've watched a lot of reports from people that enjoy that and go there. I think I would hate it personally because of the crowds and the drugs and partying. It's not really my thing. But most of the reports I've heard of people from from Burning Man and Burning Man like events are wildly positive. They say they're, you know, some of the best most spiritual experiences of their lives. And the whole of Burning Man is pretty great if you get down and look into the anti-capitalism and art and free love and all that jazz. I don't see how you can look at that with such negativity. He went out to the desert to have a good time and had a good time. And that's all there is to it.
|
||||||
|
|
||||||
|
SHANICE: Yeah, I hear you. And honestly, looking at those pictures again, he looked happy, really happy, like genuinely having the time of his life.
|
||||||
|
|
||||||
|
LUKE: And when's the last time I saw him look like that here. So yeah, you should talk to Raymond and maybe ask him if you can go with him this year and see what it's about and have a more informed viewpoint of what's going on there before you start trying to destroy the guy's life and reputation for it.
|
||||||
|
|
||||||
|
PATTY: Oh man. Can you imagine me at Burning Man? I'd be the person bringing a cooler and asking where the bathrooms are. But you're right, Luke. I called in here ready to justify being Patty. And you just made me realize I'm jealous. I'm jealous that he went out and something wild and I'm still here in the same workshop mounting the same animals for the same clients.
|
||||||
|
|
||||||
|
LUKE: Well, get out there and do something wild and maybe enjoy your life a little bit more and don't worry so much about what Raymond says. You know, you know what you've got to do in your life. You don't have to take his advice. Maybe he'll give it when it's unsolicited and you can just ignore it. But it sounds like he's a decent man that is speaking to you with the best of intentions.
|
||||||
|
|
||||||
|
PATTY: You're absolutely right. I'm going to keep my mouth shut at poker. And maybe next time he starts lecturing me about living right, I'll just smile and let it roll off. He's trying to help in his own way, even if it drives me crazy sometimes. And honestly, finding those photos was probably the best thing that could have happened. Because now when he gets on his high horse, I can just picture him in that harness and light up goggles. And it'll take the sting out of it.
|
||||||
|
|
||||||
|
LUKE: Excellent. See, that's what we do here. Look at the Roots. We bring families back together. Uh, thank you for the call. I hope everything goes well with your uncle. And now it's time for a word from our sponsors. This episode is brought to you by Desert Gut, the all-in-one nutritional supplement made from things you'd actually find within walking distance from my RV. Each scoop of Desert Gut contains 17 adaptogens, nine minerals scraped directly off a rock, pulverized tumbleweed fiber, and a proprietary blend we're calling coyote dust. which our lawyers have asked me to clarify as not made from actual coyotes. Desert gut tastes like someone described the color beige to a blender, but you'll feel incredible, or you'll feel something. First five callers get a free shaker bottle that definitely used to be a gas station coffee cup. Desert gut, because your gut isn't going to desert itself. All right. to the show. And now on the phones we've got T-Bone. Teabone, welcome to the show.
|
||||||
|
|
||||||
|
T-BONE: Luke, hey, yeah, I'm calling about my sister's gender reveal party tonight. And I got to tell you, this thing got completely out of hand. I'm talking a D, J, a catered taco bar, 200 people in my backyard. And at the end of it all, she shoots off this confetti cannon that covers my entire property and pink glitter.
|
||||||
|
|
||||||
|
LUKE: What did you expect was going to happen at a gender reveal party?
|
||||||
|
|
||||||
|
T-BONE: Well, I expected maybe. be, I don't know, a cake, some balloons, not a full production with the sound system, and a guy in a bowtie handing out shrimp cocktails. I've got five acres out in the desert, Luke, and she turned my property into some kind of festival grounds.
|
||||||
|
|
||||||
|
LUKE: Well, I mean, it's a gender reveal party. I think the people that are interested in a gender reveal party are maybe a little bit on the dramatic end of things, and they think their news there is very, very important. So you can understand why maybe they acted that. way.
|
||||||
|
|
||||||
|
T-BONE: Okay, but here's the thing. I teach middle school, Luke. I deal with drama all bay long, 13-year-olds crying because somebody unfollowed them on Instagram. And I come home to my sister doing basically the same thing, except she's 34 years old and spent what had to be two grand announcing whether her kids got a penis or not. I mean, my coworker Deshaun said it to me straight at lunch yesterday. Nobody cares this much about baby gender.
|
||||||
|
|
||||||
|
LUKE: Wouldn't it be funny if that child grew up to have a different gender identification?
|
||||||
|
|
||||||
|
T-BONE: I mean, yeah, that's the other thing. She's over here acting like this pink confetti is some kind of binding contract with the universe. Like, what if the kid decides differently down the road? Then what? She going to shoot off another cannon in 15 years? Look, I don't care what the kid ends up being. I just think the whole spectacle is ridiculous.
|
||||||
|
|
||||||
|
LUKE: I agree with you. That is a ridiculous spectacle, and it's completely unnecessary. but, you know, you agreed, and you knew what a gender-reveal party was, so I guess you've got to clean up some of that confetti. But luckily you live in the desert, so it's all going to blow away probably by tomorrow.
|
||||||
|
|
||||||
|
T-BONE: Well, that's the thing, Luke. It's not blowing away. It's this heavy-duty stuff, like industrial glitter mixed with paper. And my chickens are out there eating it right now. I raise heritage breed Wyandots. And I got no idea if this stuff is going to mess with their digestive system.
|
||||||
|
|
||||||
|
LUKE: Nothing messes with their digestive system. system. Worst case scenario, you're going to have pre-decorated Easter eggs.
|
||||||
|
|
||||||
|
T-BONE: Huh. Yeah. Pink-glitter chicken eggs. That'll go over real well at the farmer's market. But seriously, I didn't even want to say yes to this thing. She asked me two months ago, and I should have just told her no. Use your own yard. But she lives in one of those H-O.
|
||||||
|
|
||||||
|
LUKE: What's an H-O?
|
||||||
|
|
||||||
|
T-BONE: H-O-A, Homeowners Association. She's in one of those cookie-cutters' subdivisions where you need written permission to change your mailbox color. So she can't do anything fun at her place. And I'm out here with five acres, and apparently that makes me the family event venue now. I got a Silverado in the driveway, some land. And suddenly, every birthday, every baby thing, it's, can we use your place, T-bone? And I keep saying yes because she's my sister. But man, I'm getting tired of being the backup plan for people who chose to live in places with rules.
|
||||||
|
|
||||||
|
LUKE: Well, you're going to have to stand up for yourself and say, that you made a mess out of my place the last time and I don't want to pick it up. So next time just say, no, we're going to do this at your place. Or you're going to have to reel in your party so that it fits within the allotted rules of your HOA.
|
||||||
|
|
||||||
|
T-BONE: You're right. You're absolutely right. I just, I don't know why I can't say it to her face. I can tell 13-year-olds all day long that their essays late, and I'm not accepting it. No exceptions. I can stand in front of 30 kids and lay down the law about cell phones. But my My sister asked me for something, and I just fold.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, it's pretty easy to tell a kid what to do. You have an interesting power dynamic there, but with family, it's a little bit different. Still, if you want to be a man, then stand up for yourself and say what you want, what you will accept, and what you will not accept.
|
||||||
|
|
||||||
|
T-BONE: Yeah, you're calling me out, and I hear you. I make decent money teaching. I owe my property outright. I bench 225. I shouldn't be acting like I can't set a boundary with my own sister. It's just she's going through a lot right now, you know? Her husband works offshore two weeks at a time. She's about to have this baby. And I think part of me feels like I should just suck it up and help out.
|
||||||
|
|
||||||
|
LUKE: Well, you've got to pick one or the other. You can suck it up and help out and do whatever it is that she wants and then clean up her industrial-grade glitter from your chicken's assholes. Or you can say, no, I don't want to do that anymore. You're going to have to find another place. But that's completely up to you. And you're going to be. going to have to make that choice based on how you want to live your life.
|
||||||
|
|
||||||
|
T-BONE: You know what? You're right. I'm sitting here complaining to you at midnight about glitter, when I could have just said no two months ago. Her husband makes good money on those rigs. Way more than I make teaching. They can afford to rent a pavilion at a park, or do this thing at a restaurant like normal people. I don't need to be the solution every time, just because I've got the space.
|
||||||
|
|
||||||
|
LUKE: Next time she asks, I'm telling her straight up. Find somewhere else. There you go. That's standing up for yourself. That's what I always say. Stand up for yourself. Do the right thing. And then you don't have to clean up glitter. We're going to take one more call tonight because it's getting a little bit late. And the last caller here we've got on the line is Mavis. Mavis, welcome to the show. You're the last caller tonight. What would you like to talk about?
|
||||||
|
|
||||||
|
MAVIS: My brother owes me $8,000, and I'm about to take his dogs.
|
||||||
|
|
||||||
|
LUKE: Wait, what? You're going to steal his dogs?
|
||||||
|
|
||||||
|
MAVIS: Not steal. Collateral. He borrowed $8,000 to fix his roof back in October. Said he'd pay me back by Christmas. Well, it's almost March, and I came home today to find my living room trashed because he's been using my place as a kennel while I was working in Lordsburg all week. Carpets destroyed. Tea. Vs cracked and Ed when I called him. Actually laughed and said shit happens. So yeah, I'm taking two of his pointers.
|
||||||
|
|
||||||
|
LUKE: Do you even like dogs?
|
||||||
|
|
||||||
|
MAVIS: Like them. Luke, I trained those dogs. That's my bloodline going back to a bitch I bought in 98. I've been breeding and training pointers for 26 years.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like you didn't do a very good job if they destroyed your house now, did you?
|
||||||
|
|
||||||
|
MAVIS: Those dogs are perfectly trained when they're handled right. My brother's lazy. He doesn't exercise them. Doesn't give them structure, just dumps them wherever it's convenient. A pointer needs work. They need routine.
|
||||||
|
|
||||||
|
LUKE: Well, I mean, I hope that works out for you. I don't think you can just take somebody's dogs. I mean, I would never let anybody take my dog. So if he's going to just allow you to take his dogs, I don't know what says about him.
|
||||||
|
|
||||||
|
MAVIS: He's not going to allow it. I'm just going to do it. I've got keys to his place and I know his schedule. He works nights at the mine Thursday through Sunday. I'll go Friday morning, load them up, and he can come get his money together if he wants them back.
|
||||||
|
|
||||||
|
LUKE: And what happens if he calls the police on you?
|
||||||
|
|
||||||
|
MAVIS: And tell them what? That his sister took back the dog she bred and trained because he owes her $8,000 and destroyed her house? I've got the vet records. I've got the category papers with my name on them. I've got text messages about the loan. He's not calling anybody.
|
||||||
|
|
||||||
|
LUKE: I don't think it works that way. If they're his dogs, you can't just take them, even if you have the training papers. I mean, that'd be like any trainer that trained a dog coming and just taking the dog back. It doesn't work that way. And people have a severe amount of sympathy for dogs and pet owners. So if somebody's missing their dogs, you're not going to have a public opinion on your side here.
|
||||||
|
|
||||||
|
MAVIS: Public opinion. Luke, this isn't about public opinion. This is about my brother thinking he can walk all over me because I'm always the one who bails him out. I loaned him money for his roof. I trained his dogs for free. I let him use my house. And every single time he takes advantage. The dogs are leverage. He gets them back when I get my money back.
|
||||||
|
|
||||||
|
LUKE: Okay, well, I hope that works out for you. You sound like somebody I wouldn't want to fuck with.
|
||||||
|
|
||||||
|
MAVIS: You're damn right. I've been too nice for too long, and look where it got me. Three grand in repairs and a brother who laughs about it.
|
||||||
|
|
||||||
|
LUKE: Well, you know what could have? I mean, you could take those dogs and then find out one of them has cancer, and now you're on the hook to pay for this dog that's not yours. Chemotherapy.
|
||||||
|
|
||||||
|
MAVIS: Then he can come get his sick dog and pay me what he owes. I'm not keeping them forever, Luke. I'm holding them until he pays up.
|
||||||
|
|
||||||
|
LUKE: What if he doesn't pay up?
|
||||||
|
|
||||||
|
MAVIS: Then I've got two excellent bird dogs that I train myself, and he's got a debt he'll never forget. Either way, I'm done being the family dormant. He'll pay. He loves those dogs more than he loves most people.
|
||||||
|
|
||||||
|
LUKE: All right, then I wish you luck, and I wish those things. Dogs look, it seems a little fucked up that you're making those dogs collateral on a loan to your own family. That's a bit... This whole scenario seems a little bit excessive.
|
||||||
|
|
||||||
|
MAVIS: Excessive? He destroyed my living room, Luke. My carpets ruined. My TV's cracked. My favorite movies snapped in half. I came home after a week taking care of a stroke patient, and my house looked like a frat party happened in it. And when I called him Ed?
|
||||||
|
|
||||||
|
LUKE: Why'd you call him Ed?
|
||||||
|
|
||||||
|
MAVIS: Oh, that's his name. Ed. Edward. But nobody calls him that. He's always been Ed to me.
|
||||||
|
|
||||||
|
LUKE: All right. Well, good luck to Ed. Jesus Christ. You sound like Satan.
|
||||||
|
|
||||||
|
MAVIS: Satan would have taken the dog six months ago when he brought my truck back on empty. I gave him a pass on that one. Not this time.
|
||||||
|
|
||||||
|
LUKE: All right. Well, it sounds like you've got it all figured out. So I wish you the best and I wish those dogs the best. And fuck, I wish Ed the best.
|
||||||
|
|
||||||
|
MAVIS: You think I'm being too harsh.
|
||||||
|
|
||||||
|
LUKE: Slightly. Luke. I told him what happened and he said shit happens and laughed. Like it was nothing. Like I'm supposed to just eat $8,000 in a destroyed living room because we share DNA.
|
||||||
|
|
||||||
|
MAVIS: Hey, you gotta do what you gotta do. So go do it. And I wish everybody the best in this whole scenario.
|
||||||
|
|
||||||
|
LUKE: I'm glad that you're not mad at me.
|
||||||
|
|
||||||
|
MAVIS: I'm not mad at you. I'm mad at him. And I'm mad at myself for letting it get this far.
|
||||||
|
|
||||||
|
LUKE: Okay. Well, thanks for the call. And I hope you get a good night's sleep and maybe think about this overnight. time and see if it's what you really want to do, all right?
|
||||||
|
|
||||||
|
MAVIS: Yeah. Yeah. All right. Thanks for listening, Luke.
|
||||||
|
|
||||||
|
LUKE: Wow. Jesus. I am glad that I haven't pissed off Mavis. Wow. All right. Well, that's the end of our show, folks. Thanks for tuning in again, and we'll talk to you tomorrow. Bye-bye.
|
||||||
@@ -0,0 +1,287 @@
|
|||||||
|
LUKE: All right, welcome back. I'm Luke. I'm your host of tonight's show, Luke at the Roost. This is the call-in talk show where you can call in with whatever's going on in your world, and I'll give you the best advice that I can, which will probably be horrible advice. If you'd like to give us a call, the number's 208-439-583. That's 208-439 Luke. If you're not near your phone and you'd like to participate in the show, you can send us an email at any time. The email address is submissions at luke at the roost.com. Now we're starting the show a little bit early today because I can, and our phones are already lighting up. So we're going to go to the phones and see what's going on. First up, we have Donnie. Donnie, welcome to the show. What's happened? What can we help you with today?
|
||||||
|
|
||||||
|
DONNIE: Hey, yeah, Luke. Thanks for taking the call. So I was reading about this thing called the Great Oxygenation Event. It happened like two and a half billion years ago. All these bacteria started making oxygen, and it killed almost everything on the planet just wiped it out too much oxygen
|
||||||
|
|
||||||
|
LUKE: i mean don't most things on the planet need oxygen to survive
|
||||||
|
|
||||||
|
DONNIE: well yeah now they do but back then nothing needed it it was poisoned to them all the like that existed the oxygen just it killed them
|
||||||
|
|
||||||
|
LUKE: well that's interesting do you think that's part of what uh helped spur growth as we know it today life on this planet and it was the great oxygenation from the bacteria
|
||||||
|
|
||||||
|
DONNIE: that's the thing yeah that's exactly it the catastrophe made everything else possible like us sitting here talking right now that only happens because billions of years ago everything died the poison became the thing we need i don't know
|
||||||
|
|
||||||
|
LUKE: well that's interesting the poison is the thing we need that should be the name of this episode the poison is the thing we need uh so the bacteria created a bunch of oxygen it killed off everything that was on the planet which would have been what before before oxygenated Was there just other bacteria?
|
||||||
|
|
||||||
|
DONNIE: Yeah, anaerobic bacteria. They lived without oxygen. And then the cyanobacteria show up and start photosynthesizing. And just pump all this oxygen into the atmosphere and the ocean, and it's toxic to everything else. It took millions of years, but it basically ended that world. And then after, you know, after everything's gone, that's when the new stuff can start, the stuff that uses oxygen.
|
||||||
|
|
||||||
|
LUKE: Okay, so when do you think we're due for a new? new great oxygenation or carbon dioxide nation. What are you think is going to take out life as we know it on the planet now so that the next version of life can materialize?
|
||||||
|
|
||||||
|
DONNIE: I don't know if it works like that. I mean, maybe it does. I was just thinking about how you can't always tell when you're in the middle of it.
|
||||||
|
|
||||||
|
LUKE: Well, I guess we wouldn't be able to tell because we'd be dying. But that's an interesting story. Do you have anything else to add?
|
||||||
|
|
||||||
|
DONNIE: No. I just. I've been thinking about it a lot this week, how the worst thing that ever happened was also the best thing. And you can't have one without the other.
|
||||||
|
|
||||||
|
LUKE: No, sir, you can't have one without the other. Just like, what do they say? Love and marriage. Love and... All right. Next up, we have Rochelle. Rochelle is a returning caller. Welcome back to the show.
|
||||||
|
|
||||||
|
ROCHELLE: Hey, Luke. Oh, my God. I couldn't believe my own eyes when I saw Donnie was on earlier. I was in the kitchen doing dishes and I literally had to stop because I was laughing so hard. The oxygen thing, killing everything off to save everything, that was beautiful, man.
|
||||||
|
|
||||||
|
LUKE: Ah, yeah, killing everything off to save everything. It's hilarious. I understand. What are you calling in for today, Rochelle?
|
||||||
|
|
||||||
|
ROCHELLE: Okay, so I did it. I broke up with Marcus like two weeks ago. And I've been doing the whole single thing, right? Like really trying to sit with myself, not jump into anything. I even deleted the dating apps.
|
||||||
|
|
||||||
|
LUKE: Okay, and how's that working out for you? What are you filling your time with, and if it's not random men?
|
||||||
|
|
||||||
|
ROCHELLE: Well, that's the thing, though. I've been filling it with, I mean, I've been good. I've been taking the kids to this new trampoline park over in Rio Rancho on weekends. Been helping Rosa with her garden, which is actually really nice.
|
||||||
|
|
||||||
|
LUKE: Well, congratulations. Good for you. Did you have a problem or an issue that you wanted to talk through on the show, or you're just calling to give us an update about your relationship status?
|
||||||
|
|
||||||
|
ROCHELLE: No, there's definitely something. So David texted me last Thursday, my ex-husband, first time since I turned off the location sharing thing. And he said he wanted to drop off some boxes of my stuff he found in his storage unit.
|
||||||
|
|
||||||
|
LUKE: All right, do you know what's in the boxes? Obviously, you're missing the stuff, so have you identified which of your own stuff you're missing?
|
||||||
|
|
||||||
|
ROCHELLE: That's what I asked him. I was like, what stuff? Because when we split everything up, I was so careful. I made spreadsheets, Luke. I had a whole system.
|
||||||
|
|
||||||
|
LUKE: What's in the box? Do you think it's maybe a severed head or just an excuse for David to come talk to you again?
|
||||||
|
|
||||||
|
ROCHELLE: Oh, it's definitely an excuse. I know that. He told me it was like old photo albums and some kitchen stuff. But when he brought them over on Saturday, it was just, it was my old college textbooks.
|
||||||
|
|
||||||
|
LUKE: Oh, so he already brought the boxes over. All right. So what did he have to say for himself?
|
||||||
|
|
||||||
|
ROCHELLE: He stood on my porch for like 40 minutes, just talking. Started with the boxes. Then he's asking about the kids. how he joined this hiking group, and they went up to the Sandia's last weekend. And the whole time I'm just standing there in my doorway, and I couldn't believe my own eyes, because he looked. Good, you know?
|
||||||
|
|
||||||
|
LUKE: So obviously you're really taking this single thing to heart, huh?
|
||||||
|
|
||||||
|
ROCHELLE: Okay, yeah, I hear how that sounds. But I didn't invite him in or anything. I kept it on the porch. And then yesterday, Angie, my cousin, she calls me and says she saw David at Trader Joe's, and he was buying all this fancy cheese and wine, like date night stuff.
|
||||||
|
|
||||||
|
LUKE: Well, I don't drink wine, but I sometimes enjoy a fancy pepperjack. So maybe he just enjoys wine and cheese, and that's what he was doing. I mean, I don't think you need to concern yourself with what David's doing. You're a single woman, and you're refinding yourself right now. So stop worrying about David and other dudes, and keep working on your garden and finding ways to move forward in your own life.
|
||||||
|
|
||||||
|
ROCHELLE: You're right. You're completely right. The thing is, is, though, I looked at the app again after he left, just to see. And I know I turned off sharing my location with him, but I can still see his if I want to. And he never turned his off for me.
|
||||||
|
|
||||||
|
LUKE: All right, well, you're being a little bit crazy now, and I think you should just get rid of that app. You told me already you deleted the apps, and obviously you haven't. So you're lying to me, you're lying to yourself. And if you want to move forward with your life, then move forward with your life. And if you want to, you know, rekindle whatever relationship you have with this dude, do that. But But it's not very interesting for this show. You're back and forth here.
|
||||||
|
|
||||||
|
ROCHELLE: Okay. Okay. You're right. I'm deleting it right now. I'm doing it. But can I just tell you one more thing?
|
||||||
|
|
||||||
|
LUKE: Yes, you can. What is that thing?
|
||||||
|
|
||||||
|
ROCHELLE: Sunday night, I drove past the Sonic where he parked that time, the one near my house. And his Tacoma was there. Same spot. And I sat in the Dairy Queen parking lot across the street for like 20 minutes just watching his truck. And I realized he probably saw me.
|
||||||
|
|
||||||
|
LUKE: Okay, so you're really just painting a picture of yourself as a main. and you really need to stop. I don't know why you think I would think that this is interesting, but I don't. Okay, so if you want some advice and you're going to take the advice, I'm happy to give it to you. But if you just want to tell me about, you know, David, I really don't care.
|
||||||
|
|
||||||
|
ROCHELLE: No, I want the advice. I'm sorry. I know I sound crazy.
|
||||||
|
|
||||||
|
LUKE: Well, thank you for the call, and we hope that you don't call us again tomorrow with the same shit, Rochelle. You're going to have to figure out your life there, because I don't have any advice for you that you're going to take. So, next up on the line, we got Mikey. Mikey, welcome to the show. What's going on in your life?
|
||||||
|
|
||||||
|
MIKEY: Hey, Luke, thanks for taking my call. So I just dropped off this Tesla, right? And the whole ride back this guy's going on about his grind, how he's up at 4 in the morning, working until midnight, hasn't seen his kids awake in weeks, and he's saying it like it's a good thing, like he's winning. And I'm sitting there thinking, man, I used to be you.
|
||||||
|
|
||||||
|
LUKE: Yeah, I think we all did. That's part of our culture. It's to grind and work and grind and always be busy. And I think we've learned through study after study that that's not any way to live. And it's a good way to burn yourself out and get taken advantage of by exploitative employers.
|
||||||
|
|
||||||
|
MIKEY: Exactly. And here's the thing that got me. This guy couldn't have been more than 30, and he already looked like he needed a defibrillator, like physically looked bad. And I'm watching him and I'm like, dude, I burned my second marriage to the ground doing exactly what you're doing. I thought saying yes to every call, every hour, every toe in the middle of the night was proving something.
|
||||||
|
|
||||||
|
LUKE: Well, sometimes you can do that and sometimes you can't, you know, but everybody has to learn for themselves where their limits are and learn how to stand up for those limits. the hard part that a lot of people never get is, when is it time to say no? When is a time to step back? And how much forward momentum is really necessary without harming yourself and the rest of the things in your life?
|
||||||
|
|
||||||
|
MIKEY: Yeah, and that's what I never figured out until it was too late. Like, I didn't know how to say no because I thought the work was the point. I thought if I just kept showing up, kept grinding, that would be enough. But my ex-wife, she didn't leave because I wasn't making money.
|
||||||
|
|
||||||
|
LUKE: Why did she leave?
|
||||||
|
|
||||||
|
MIKEY: She left because I wasn't there. Like, physically I'd come home, but I was already thinking about the next call, the next job. I'd be sitting at dinner and my phone would go off and I'd just get up and leave every time. And she'd say, can't someone else get it? And I'd say, this is what pays the bills.
|
||||||
|
|
||||||
|
LUKE: Yep, and I think you've learned that there's more to life than paying bills. And that's a lesson that we all have to learn. In this world, I think we're starting to understand that, especially after COVID. the whole COVID situation really opened people's eyes up to how much we were wasting on capitalism.
|
||||||
|
|
||||||
|
MIKEY: Yeah. Well, here's the kicker, though. I still don't know if I actually learned it. Like, I'm still taking every call. I'm still out there at two in the morning hauling in some drunks Camry. The difference is now I don't have anyone waiting up for me. So it doesn't feel like I'm letting anybody down, which is maybe worse. I don't know.
|
||||||
|
|
||||||
|
LUKE: Well, it's a balance, right? If you're at a special spot in your life where you don't have anything else going on. Maybe that is the best use of your time. If it's keeping you occupied, you're being productive, and there's nothing that you're letting fall by the wayside, like your own personal health and nutrition and peace of mind, then good. You can do that. But you have to know when to ramp up and when to ramp down. And at some point in the future, you're going to want to have some sort of meaningful relationship with people or be involved in your community or take on some sort of volunteer or philanthropy or something like that. There's more to life than work. And if you put all of yourself into your work forever, I mean, at the end, you're not going to get anything out of it.
|
||||||
|
|
||||||
|
MIKEY: You're right. And I know you're right. But here's what scares me. I've been filling the time with other stuff. Like, I go home and I watch these quantum physics videos until three in the morning. Just completely fall down these rabbit holes about particle entanglement and the observer effect.
|
||||||
|
|
||||||
|
LUKE: Okay, but that's not really filling your life with other stuff. stuff is that's just consuming content to go to bed. That's not doing anything meaningful or making relationships or moving forward any personal goals. It's, uh, I don't want to say wasting time because you're learning and you're listening to something that you find interesting, but it's, it's not what I'm talking about. I'm talking about, uh, getting something out of life, a project, hobby, uh, friendships, um, some, some, uh, greater purpose or meaning or, uh, involvement with your community and the world.
|
||||||
|
|
||||||
|
MIKEY: Yeah, no, you're absolutely right. I'm just swapping one way of checking out for another. Like, before it was burying myself in work so I didn't have to deal with anything? And now it's burying myself in videos about the double-slit experiment, so I don't have to think about the fact that I haven't had a real conversation with someone in weeks. My phone goes off, I answer it, I hook up a car, I drop it off, I go home, I watch videos. I fall asleep. That's the whole loop.
|
||||||
|
|
||||||
|
LUKE: And that might be okay for you right now at where you're, at in your life. But just make sure that the remainder of your life isn't just that. Because that's very small. And there's a lot more out there to experience and to be a part of and to contribute to. So do what you have to do now to get yourself through and pay your bills and keep yourself moving forward. But don't forget that there's a lot more to life than just working.
|
||||||
|
|
||||||
|
MIKEY: You know what gets me, though? That Tesla guy tonight, the one I picked up, he's doing the same thing I did. He's 30 years old, hasn't seen his kids awake in weeks, and he's proud of it. He's bragging about his 4 a.m. cold plunges and his 18-hour days like it's some kind of badge of honor. And I wanted to tell him, man, you're going to wake up one day and realize you traded everything that mattered for a bunch of nothing.
|
||||||
|
|
||||||
|
LUKE: Well, that's the thing that everybody has to learn for themselves, right? And I think that we all, and collectively as a society, are learning that, especially as we see continuous mass layoffs of people and the loyalty erosion of corporate America and just the current state of our country. I think we understand that we've been kind of chasing this line of bullshit. And something has to change if we want to have happy, productive, fulfilled lives. So learn that for yourself.
|
||||||
|
|
||||||
|
LUKE: And you can't, you can't, you can't teach it to anybody. They have to get to a place where they realize it on their own. So he's 30. 30's still pretty young. He's right about at the state where he should kind of be figuring that out because everything in his life is going to fall away. And all he's going to have is, you know, work. And it's not even particularly interesting work.
|
||||||
|
|
||||||
|
MIKEY: Yeah, and that's the thing. I couldn't say anything to him because what am I going to say? Look at me. I'm the guy who already learned this lesson, and I'm still doing the exact same thing just alone now. At least he's got the kids somewhere, even if he's not seeing them. I don't even have that anymore. My ex moved on, remarried some accountant who's home for dinner every night.
|
||||||
|
|
||||||
|
LUKE: Everybody's path is different, man. If some people don't want to be home every night, that's boring to them. That's not fulfilling, you know, what they want out of their life. They want to be out doing stuff traveling. If your work takes you to the places you want to be to interact with the people you want to interact with, great. Then you can get two birds stoned at once. But largely it doesn't. And I think we just chase it for some, I don't know, false notion of what we're supposed to do. I think we've been trained that way from school all the way up. And we're learning now through numerous scientific studies that it's not good for us. So people are waking up. And you should too, when you're ready.
|
||||||
|
|
||||||
|
MIKEY: I hear you. I think part of it is I don't even know what I'd do with myself if I wasn't working or watching videos. What does that even look like? I go to some community center and play bingo? Join a book club? I'm not being a smart ass. I genuinely don't know what the next step is.
|
||||||
|
|
||||||
|
LUKE: Maybe it is. If you like bingo and you like your community, then hanging out at the community center isn't a bad thing. I mean, you might find out that they need your help and some of your special skills to keep the community center rolling. Or, you know, you could take up hiking or travel or photography or music or any kind of hobbies that you're into or wanted to be into. You could start a business. You can use that knowledge that you have to run your own YouTube channel and talk about, you know, your quantum physics stuff. There's tons of avenues that you can take. It's just you don't want to sit around and rot away and only consume content and work. Right? That's, you might as well be dead.
|
||||||
|
|
||||||
|
MIKEY: That last part hit me. You're right. I've got all this knowledge rattling around in my head about quantum mechanics, and I'm not doing anything with it except using it to fall asleep. I could actually share that stuff. Make it make sense for people.
|
||||||
|
|
||||||
|
LUKE: You can try. I mean, you're going to have to go a little deeper than the double split experiment because there's certainly enough content about that and it's not that difficult a concept to grasp. So I would recommend veering out a little bit into something a little more unique than the double split experiment. It's been kind of done to death. But if you're into quantum physics, I'm sure you can find a way to make that interesting and maybe make it your career.
|
||||||
|
|
||||||
|
MIKEY: doesn't have to be your career. It just do something, you know, even if it's just for you and nobody sees it. Yeah, no, the double slit is just where I started. I've been going down all these rabbit holes about quantum entanglement, the measurement problem, all that stuff. There's this one thing about quantum tunneling that blows my mind. Particles passing through barriers, they shouldn't be able to get through.
|
||||||
|
|
||||||
|
LUKE: Well, there you go. Maybe you can come up with some sort of demonstration of that or, you know, do some research and get your yourself into academia. And if that's your thing, that's your thing. And that's what you should do. But, hey there, we got to get to our sponsors here, Mikey. So if you have anything else to finish up with, I'll let you do that, and then I got to go.
|
||||||
|
|
||||||
|
MIKEY: No, I appreciate you letting me ramble. I think I needed to hear some of this stuff tonight. Maybe I'll actually do something with it instead of just letting it sit in my head.
|
||||||
|
|
||||||
|
LUKE: All right. Thanks, Mikey. I hope that, you know, you continue doing what you've got to do to move yourself forward and then when it's time, you can expand your life into the other areas where you can get the maximum fulfillment out of it. And that was time for a word from our sponsors. I used to sleep on a rolled up horse blanket. I'm not saying that for sympathy. I'm saying it because Pillow Forever asked me to establish a before state, and that's mine. Pillow Forever is a memory foam pillow that remembers your head shape so you don't have to. It's got cooling gel, bamboo fiber, and a 30-night risk-free trial, which means you can sleep on it for a month and then send it back, and someone in a warehouse is to deal with that. Every pillow forever comes in a box that's too small, which is part of the experience. You open it? And it slowly expands like a nature documentary. My dog tried to fight it. Pillow forever. You deserve better than a horse blanket. You deserve better than a horse blanket. That's what we always say here, at Luke on the roost. And next up, we got Nikki. Nicky, Nikki, welcome to the show. What's going on?
|
||||||
|
|
||||||
|
NIKKI: Hey, Luke, yeah. Hi. Am I on? Okay. Um, sorry, I know it's late to be calling. So I run a dog grooming business down in animas. Been doing it about three years now. And I have this business partner.
|
||||||
|
|
||||||
|
LUKE: All right, what about your business partner? Tell us about your business partner.
|
||||||
|
|
||||||
|
NIKKI: So Jason came in about a year and a half ago. I needed help with the books, the scheduling, you know, the business side of things, because I'm good with the dogs, but I'm terrible at all that stuff. And he seemed great at first. Really organized had all these ideas about marketing and expanding. My sister Lena told me not to trust him. Said he had a reputation around Flagstaff for being shady, but I thought she was just being overprotective. Anyway, I could not sleep last week, just one of those nights. So I'm sitting there at like three in the morning going through our accounts, and I start noticing these withdrawals.
|
||||||
|
|
||||||
|
LUKE: Uh-oh, when somebody says the word shady in tandem with accounting, that's never good. So what are the withdrawals about?
|
||||||
|
|
||||||
|
NIKKI: Yeah, so it's almost $8,000 over the past year. Small amounts, You know, 300 here, 500 there, nothing that would jump out at you if you're just glancing at the monthly statements. But when I went back and cross-checked them against the actual receipts and deposits, they don't match up. Money's just gone.
|
||||||
|
|
||||||
|
LUKE: That's a little thing we like to call fraud. So have you talked to any of the authorities about this?
|
||||||
|
|
||||||
|
NIKKI: No, not yet. I confronted Jason yesterday afternoon. Showed him everything I found. All the discrepancies laid out. And Luke, he just leaned back in his chair and smiled at me. Like this calm, easy smile.
|
||||||
|
|
||||||
|
LUKE: Okay. That's maniacal. And then what happened? Did he say anything in response? Or did you just smile awkwardly and then you left?
|
||||||
|
|
||||||
|
NIKKI: No. He said two words. He said, prove it. That's all he said. Just prove it with that smile. And then he got up and left the shop. And the thing is, I keep going over it in my head. Like, what does that mean? Does he have the receipts hidden somewhere?
|
||||||
|
|
||||||
|
LUKE: I would call the cops because it sounds like he's ripping you off. And it sounds like you can prove it.
|
||||||
|
|
||||||
|
NIKKI: That's what Lena said when I called her, but I keep thinking, what if I'm wrong? What if there's some explanation I'm missing? I've been sitting here on the floor of the shop for four hours going through everything again, and the numbers are right there, but he seemed so confident. Like he knows something I don't.
|
||||||
|
|
||||||
|
LUKE: Well, maybe he does, but I would engage the authorities sooner rather than later, because now he knows that you're onto him, and the more time you give him, the more concrete he'll be able to make his defense.
|
||||||
|
|
||||||
|
LUKE: So catch him as quickly as you can before he has to time to cover anything up.
|
||||||
|
|
||||||
|
CALLER: You're right. God, you're right. I've been sitting here like an idiot, second-guessing myself when I should have called the police this afternoon. I just kept thinking maybe I'm overreacting, maybe I misunderstood something, but $8,000 doesn't just disappear. And I trusted him. That's the part that makes me feel so stupid.
|
||||||
|
|
||||||
|
LUKE: Well, that's the thing. You can't trust anybody. And that's just the way the world is. So you trusted him. It looks like he burned you. He gave you every indication that he did, in fact, burn you, and now you have to take whatever steps you can to protect yourself. And that's to immediately call the authority. So you should do that and let them know what happened and try to catch him before he leaves town with your $8 grand.
|
||||||
|
|
||||||
|
CALLER: Yeah, yeah, I'm going to call them as soon as we hang up. I've got all the paperwork right here. Everything's documented. You know what the worst part is?
|
||||||
|
|
||||||
|
LUKE: What is the worst part?
|
||||||
|
|
||||||
|
CALLER: Lena told me not to go into business with him. Before she moved to Flagstaff, she said Jason was sketchy, that he'd burned people before. And I told her she was being paranoid, that he seemed like a good guy.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, all con men seem like good guys. That's sort of the job. I mean, that's what they do. And it's, you don't have to feel shame in getting fleeced by this guy. I mean, that's their skill. That's what they're good at. So just get off the phone with me, call the police, and start whatever proceedings you have to to get your money back as soon as you can.
|
||||||
|
|
||||||
|
CALLER: You're right. I'm doing it now. Thank you, Luke.
|
||||||
|
|
||||||
|
LUKE: All right, good luck. And that is why we don't. Don't partner with people because partners burn us every fucking time. And next up, we've got Frankie. Frankie, welcome to the show. What's going on?
|
||||||
|
|
||||||
|
FRANKIE: Hey, Luke, thanks for taking my call. So I'm a home health nurse, right? And two days ago, I found out my neighbor Dale has been running surveillance on the whole street with his ring camera. Like, full spreadsheets.
|
||||||
|
|
||||||
|
LUKE: Full spreadsheets of what? What kind of information? Like what time people are walking by or like when they walk their dogs? What could he possibly be spreadsheets?
|
||||||
|
|
||||||
|
FRANKIE: time stamps of when everyone comes and goes, what vehicles were driving, notes about who's visiting who. I found out because his ex-wife is one of my patients. She's got MS. I see her twice a week. And she showed me the file on her laptop. There's an entry from me that says, 247 a.m. White sedan unknown from when I got back from an overnight shift. The guy's literally keeping tabs on the whole neighborhood, like he's running a stakeout.
|
||||||
|
|
||||||
|
LUKE: That's a pretty weird thing. I don't legal for him to do with his home video camera to just watch the footage and then take note of everything that happens. It's creepy and it's weird and it's wrong and I'd be pissed off about it, but I don't think it's illegal.
|
||||||
|
|
||||||
|
FRANKIE: Oh yeah. No, I looked it up. Totally legal as long as the cameras pointed at his own property and the street, which is public. That's not even the part that's driving me crazy. It's that now I can't stop thinking about it. Like, I've been staying at my cousin Rubin's place in Magdalena for three nights now because I don't want to give Dale the satisfaction of logging my schedule.
|
||||||
|
|
||||||
|
LUKE: I don't know if that's the way I'd go with it. I mean, you can, but I would rather mess with Dale's data. Like, get a bunch of friends to drive around at random times and kind of poison his spreadsheet, so he thinks he's got this great database of information, but it's all nonsense. I mean, that's how we're going to defeat AI. If you want to defeat AI, the only way to do it is defeat it bad information.
|
||||||
|
|
||||||
|
FRANKIE: Oh, man, that's actually brilliant. I could get the over-neighed night crew from work involved. We're all degenerates anyway. Half of us are coming and going at weird hours. Just flood his data with noise until he can't tell what's real anymore.
|
||||||
|
|
||||||
|
LUKE: Yeah, make him so busy logging nonsensical data that is not useful. But keep in mind, if there ever is an issue when you need that data from him for some reason, if there's ever a theft or a home invasion or just some kid smashing pumpkins or stealing Amazon packages, it could be good to have somebody like that in your neighborhood that knows everything where you can go and get that authoritative source of what's going on.
|
||||||
|
|
||||||
|
FRANKIE: Okay, see, that's the thing, though. Dale's not doing this to be helpful. This is the same guy who called the cops on the Martinez family last year because their nephew was visiting from Albuquerque. And Dale decided a brown kid in a hoodie sitting in a car was suspicious activity. Turned out the kid was just waiting for his aunt to get home from work. And, listening to music. Dale's not neighborhood watch. He's neighborhood paranoia with a spreadsheet. And honestly, I think he might be living in his truck.
|
||||||
|
|
||||||
|
LUKE: He's living in his truck, but he's using his house ring camera to collect this data. That's a little weird.
|
||||||
|
|
||||||
|
FRANKIE: Yeah, his ex-wife kicked him out like six months ago, but he still owns the house, so the ring camera's still up. I've seen his F-150 parked in different spots around town at night, with the windows fogged up. The whole thing is just sad, honestly. Like, I started this call ready to make it into a bit about suburban surveillance state nonsense, but now I'm realizing I'm hiding out at my cousin's place watching Severance for the third time instead of just going home because I'm letting some divorced guy in a truck get in my... my head. That's pathetic, right?
|
||||||
|
|
||||||
|
LUKE: I mean, it's pathetic on a couple of different levels, for you and for him, and it's sad all the way around. But I think one way to deal with this would be to just go, you know, knock on his F-150 window and ask him, you know, what the hell? You're recording me and I don't like it and ask him to stop.
|
||||||
|
|
||||||
|
FRANKIE: You know what? You're right. You're right. I should just go talk to him like a human being instead of treating this like it's some true crime podcast I'm living in. The guy sleeping in his truck and obsessive logging traffic patterns. He's clearly not doing great. Maybe I just knock on the window. Tell him I know about the spreadsheet and ask him what he's actually trying to accomplish here.
|
||||||
|
|
||||||
|
LUKE: Yeah, maybe you two could team up and become great friends and solve crimes together. You never know.
|
||||||
|
|
||||||
|
FRANKIE: Oh, God. That's the nightmare scenario. Me and Dale in his F-150 at three in the morning. Him with his spreadsheet. Me with my work stories about patients' weird moles. Just two insomniacs convinced where the only ones keep Magdalena safe. Although, honestly, knowing my life, that's probably exactly what's going to happen. I'll update you if we start a podcast together.
|
||||||
|
|
||||||
|
LUKE: All right there, Frankie. Thanks for the call, and I hope you do start that podcast. Let us know. Give us a call back and let us know if you ever start that podcast, and I know I will listen to it. So next up here on the old phone lines, we've got Connie. Connie, welcome to the show. What's happening tonight in your life?
|
||||||
|
|
||||||
|
CONNIE: Oh gosh, hi, Luke. Thank you so much for taking my call. So I got really drunk at my daughter's eighth birthday party five days ago and nobody will talk to me about it. And I think I'm losing my mind.
|
||||||
|
|
||||||
|
LUKE: Okay. Is there any video evidence of you acting out at this birthday party? I don't think you're the first person to ever be in that situation.
|
||||||
|
|
||||||
|
CONNIE: No, thank goodness, no video. At least I don't think so. It was just other moms and some dads and my husband and his sister. But Luke, I don't remember half of it. I remember. I remember.
|
||||||
|
|
||||||
|
LUKE: Well, that's certainly embarrassing. But if this is one-time thing and it's not a pattern of excessive drinking, then, you know, everybody's entitled a couple of those. It's too bad that it happened at your kid's birthday party, but, you know, nobody's perfect.!
|
||||||
|
|
||||||
|
CONNIE: So I would say, yeah, you're probably going to get some weird looks for this for a while, but it'll blow over. And just make sure that you're not drinking like this consistently. But that's what's making me crazy, Luke. The silence. Like, my sister-in-law put her jacket on me and clearly got me to the couch. My husband was there.
|
||||||
|
|
||||||
|
LUKE: Yeah, that's embarrassing. You embarrassed yourself. It happens. It's unfortunate that it happened where it happened in front of a kid, but this is the type of thing that I think you'll all look back on in 10 years and be like, remember that time? Mom blacked out and swung naked from the pinata when she was drunk at my eighth birthday party? And everybody will laugh and laugh and laugh.
|
||||||
|
|
||||||
|
CONNIE: Oh, gosh. I wasn't naked. Was I? No, I had clothes on when I woke up. Luke, you're making jokes, but I keep thinking, what if I said something terrible?
|
||||||
|
|
||||||
|
LUKE: Then you'll have to be forgiven by your friends and family because, I mean, you were blocked out. You can't know if you said something terrible unless somebody tells you. So let's just go with you didn't until you learn otherwise. And if you did, you have to make apologies and, you know, suck that up because you acted irresponsibly.
|
||||||
|
|
||||||
|
CONNIE: You're right. You're right. I should just ask. I keep waiting for someone to bring it up, but maybe they're waiting for me to bring it up. Oh, shoot. What if they think I don't even care because I haven't apologized? I sent a text to the group chat the next day saying, thanks for a great party, but I didn't mention anything about getting drunk. Because I was hoping maybe it wasn't as bad as I thought.
|
||||||
|
|
||||||
|
LUKE: No, it probably was as bad as you thought. But you know what? Everybody's seen that happen before with other people or been, you know, the one that was doing it themselves. So people do understand. And they know what it's like to be so drunk that you don't know what happened. Or at least a lot of people do. Or they've seen somebody else act in that way. So don't worry about it too much. Just don't do it again.
|
||||||
|
|
||||||
|
CONNIE: You know what? You're making me feel better. I've been sitting in here folding laundry for five days, just replaying what I can remember over and over. My husband's watching TV in the next room right now, and I've been hiding in the laundry room because I'm so ashamed. Maybe I just need to go out there and say, hey, Can we talk about Saturday and get it over with?
|
||||||
|
|
||||||
|
LUKE: Yeah, no matter what you did, it wasn't that bad. I mean, you didn't sign over your house to the casino or get married to a hooker in Vegas or, you know, you didn't do anything that can't be fixed. So don't worry too much about it. Don't do it again. Be careful and make apologies if you have to.
|
||||||
|
|
||||||
|
CONNIE: You're absolutely right. I think I've been making it bigger in my head than it actually is. I mean, Maya had a great time at her party. all the presents she wanted. And she hasn't said anything weird to me about it, so she probably doesn't even remember much. And Bethany was doing shots with me, so she can't judge. I'm just going to talk to my husband tonight and apologize to my sister-in-law tomorrow.
|
||||||
|
|
||||||
|
LUKE: There you go. That's the way to handle it. And be careful. Watch the drinking, because there might come a time when you're in a situation where it's not so easy to recover from. With that, we have to take a small word from our sponsors. Life is hard. You're listening to a man in an RV talk to strangers at 2 in the morning, so you already know that. That's why we partnered with Better Maybe, online therapy that's honest about the whole situation. With Better Maybe, you get matched with a licensed therapist within 48 hours. Will they fix your problems? Maybe. That's the whole brand. They're not going to lie to you. Your first session might change your life. It also might just be used. staring at the webcam while someone in another time zone nods politely. That's still more than your friends are doing. Better maybe. It's better than nothing, and that's not nothing. All right, and we are back. Here we go. We've got Ray on the line. Ray, welcome to the show. How can we help you tonight, sir?
|
||||||
|
|
||||||
|
RAY: Hey, Luke, thanks for taking my call. So my neighbor set off M-80s in his driveway at 1030.30. tonight and my son ended up under the kitchen table.
|
||||||
|
|
||||||
|
LUKE: Well, how come you guys didn't go out and enjoy the festivities?
|
||||||
|
|
||||||
|
RAY: Enjoy the, Luke. It's a Wednesday night. People got work in the morning, but that's not even the thing. My son Marcos just got back from his second deployment in December. He's home on winter break from grad school. And the second those things started going off, he just dropped, like his body knew what to do before his brain caught up. I found him under the table with his hands over his head and this look on his face I haven't seen since he first got back two years ago.
|
||||||
|
|
||||||
|
LUKE: Well, that is too bad and he should maybe, I'm not sure if he is, but he should maybe be in some therapy for that post-traumatic stress. But here we are in the desert, right? These are the frontier states where people are going to blow off M80s and shoot guns. That's kind of, that's part of the appeal of this area. So it's not necessarily always a serene and quiet retreat. can really do here is talk to your neighbor and explain the situation and ask him to be a little more considerate next time.
|
||||||
|
|
||||||
|
RAY: Yeah, no, you're right. He isn't therapy. He's been going since he got back. And I get it. I do. People want to blow stuff up. It's a free country. I already went over there, told the guy about Marcos. He apologized, said he didn't know. Of course. How could he know?
|
||||||
|
|
||||||
|
LUKE: So it sounds like you've already solved this problem. What's eating at you?
|
||||||
|
|
||||||
|
RAY: I don't know, man. It's just, I keep. He's seen his face. Like Marcos is doing good. You know? He's in a master's program for engineering. He's got his life together. He comes home and we watch basketball. We go to the gym together. And then one string of firecrackers and he's right back there. And I'm standing in the kitchen doorway watching my son under the table and I don't know what to do.
|
||||||
|
|
||||||
|
LUKE: No, how could you know what to do? Did you talk to him about what to do, what he was feeling and maybe how you could be most helpful to him in that situation? I luckily have never had to go overseas or fight in any kind of war like that, so I don't have that stress reaction. But I can imagine that it's very unpleasant.
|
||||||
|
|
||||||
|
RAY: We talked after. Yeah, he was embarrassed more than anything. Kept apologizing, saying he was fine, that it just caught him off guard. I told him he didn't need to apologize to me. But he just went to his room. And that's the thing, Luke. I'm a physical therapist.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, this isn't really a physical thing. So I don't know that you really have any. qualification in this area. But I would be interested if you have the opportunity to have a more serious conversation with him about what he's feeling and what the correct way to interface with him in that moment would be. I think that would probably help both of you and the listeners here.
|
||||||
|
|
||||||
|
LUKE: If we knew, if we saw that happen to somebody, what the correct way to help them would be without making them feel worse about it, you know?
|
||||||
|
|
||||||
|
CALLER: Yeah, you're right. I'm to actually ask him instead of just standing there feeling useless. It's just hard because he doesn't want to talk about it, and I don't want to push him and make it worse.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, you don't really have to push him. You can phrase that another way. You can say, look, when that happened, I mean, you should be able to talk about the event that happened without causing a problem. So you can say, when that happened with the M80s the other night, and you were obviously in distress, I felt useless. And if that ever happens again, I want to be able to be helpful to you. So I'd like to understand what happened to you and how I could best be supportive to you in those situations, right? You can't make all loud noises stop. There's going to be Fourth of July. There's going to be somebody firing off M80s or a car backfiring. You know, that's going to happen forever for the rest of his life. So getting him past it and getting you past it together, like something that's possible if you can talk it through.
|
||||||
|
|
||||||
|
CALLER: That's good. That's really good, actually. I can do that. Because you're right. I can't bubble wrap the world for him. And he wouldn't want me to anyway.
|
||||||
|
|
||||||
|
LUKE: No, I don't think he would. And also, it's just an interesting thing that I think we all need to recognize and understand that some people have those responses to loud stimulus like that. And none of us or most of us really have no idea how to deal with that, how to react to those people. So I personally would be interested in what the right way to help somebody in that situation would be. Okay, we're going to take one more call here. And that's going to be the end of our show. So I think we'll go to Amber. Amber, thanks for calling in. You're the last caller tonight. How can we help you?
|
||||||
|
|
||||||
|
AMBER: Hey, Luke, thanks for taking my call. So I found $200 in a coat pocket. A coat I borrowed from my ex-best friend, Rachel, two years ago. And we haven't spoken since she moved to Flagstaff after this whole falling out we had and I need to know if this money is legally mine now or if I'm supposed to track her down somehow and give it back. I already looked up New Mexico Statute 30, 16, 6 on lost property, and technically, after holding onto something for two years without the owner claiming it, it becomes your property.
|
||||||
|
|
||||||
|
LUKE: Okay, well, it sounds like you went a little bit deep into this one. If it's cash money and it's in a coat and she moved away and you're in possession of the money, I wouldn't worry about it too much. I mean, how would you even get that money back to her if you wanted to? Congratulations on your new $200.
|
||||||
|
|
||||||
|
AMBER: Well, that's the thing. I could technically get it to her. I mean, I know where she works because her Instagram is public even though she blocked me on everything else. She's at this coffee roastery in Flagstaff. I could mail it or Venmo it, except she blocked me there, too.
|
||||||
|
|
||||||
|
LUKE: Yeah, I mean, it sounds like you guys had a following out. She probably doesn't really want to talk to you. If she wanted the 200 bucks back, she would have come looking for it. I'd say just pocket the money and move on or donate it. You know, give it to somebody else. But I wouldn't rekindle that friendship over $200 that's been sitting in a pocket for two years.
|
||||||
|
|
||||||
|
AMBER: Right, but here's what's eating at me. I don't actually know if it's her money. Like it could be mine from two years ago and I just forgot I put it there. Or it could be hers and she forgot. And if it is hers, and she's been struggling financially, which she might be because she moved back in with her parents after the move, then keeping it makes me the person she's she already thinks I am, which is part of why we're not speaking in the first place.
|
||||||
|
|
||||||
|
LUKE: Okay, well, if you want to give her the money back, then, I mean, mail out of the money. But I'm thinking that probably you should just pocket this $200 and move on with your life and forget about her. Because obviously you two don't want to speak to each other and she's moved away, and it was two years ago. So, I mean, this doesn't seem like a thing that has to be keeping you up at night.
|
||||||
|
|
||||||
|
AMBER: You're right, it shouldn't be keeping me up at night. But the reason I'm actually calling is because my friend Tammy from church said, the exact same thing you just said. Just keep it. It's been two years. Forget about it. And when she said that, I got so annoyed with her. Like, unreasonably annoyed. I snapped at her in the church parking lot over it. And now I'm wondering if the money is even the actual problem, or if I'm just looking for an excuse to reach out to Rachel, and this is the only one I've got that doesn't make me look desperate.
|
||||||
|
|
||||||
|
LUKE: Well, that seems to be the case, because this is not a difficult, um, uh, obstacle to, to, to, Shit, this is not a hard problem, right? You could just keep the money and be done with it. But since you don't seem to want to accept that, it seems like you want to talk to your friend that you miss. And that's okay, too. And it's perfectly okay to reach out to an old friend and say, hey, sorry, you know, things ended the way they did, but I'd like to talk to you again because I miss you. That's okay, too. If that's what you want to do, I give you permission.
|
||||||
|
|
||||||
|
AMBER: Okay, but here's the thing. I can't just say I miss her because I'm the one who messed up. She didn't end the friendship I did. She started dating this guy Trevor, who I thought was using her. And I told her that. And then I told her sister that. And then I may have also told Trevor's ex-girlfriend some things Rachel told me in confidence about their relationship. And I thought I was protecting her. But really, I was just being controlling and inserting myself where I had no business being. She found out what I did, and she was right to cut me off.
|
||||||
|
|
||||||
|
LUKE: Okay, well, it seems like you understand the problem, and you can still reach out to her and say you miss her and you'd like to re-handle the friendship and you're sorry for what you did and you won't do it again. Because it sounds like you understand that. You take responsibility for what you did wrong here. And that's a good thing. And if you miss this friendship and you want it to continue, then reach out, give her $200 bucks back and see how that goes. But also, if it doesn't go the way you want, accept that.
|
||||||
|
|
||||||
|
AMBER: Yeah, I know I need to accept that possibility. But what if giving her the money back just looks like I'm trying to buy my way back into her life? worse. What if she doesn't even remember putting money in that coat? And now I'm just reminding her that I still have her stuff after two years. Which makes me look like I've been holding on to it for sentimental reasons, which I kind of have been, honestly.
|
||||||
|
|
||||||
|
LUKE: That's okay. You don't have to think about it that much. If you want to talk to your old friend, then talk to your old friend. And if you don't, then pocket the $200 and move on. That's what I have to say.
|
||||||
|
|
||||||
|
AMBER: You're right. I'm overthinking this because I'm scared. I'll mail her the money with a note that just says I'm sorry and I miss her. And if she wants to talk, I'm here. And if she doesn't respond, then at least I tried and I can actually move on instead of sitting in this break room at two in the morning, staring at $200 bills like they're going to tell me what to do. Thank you, Luke.
|
||||||
|
|
||||||
|
LUKE: You are very welcome, and I hope that works out for you. And that, ladies and gentlemen, is the end of tonight's show. So thanks for tuning in. If you'd like to follow us, we're on all the socials or whatever social you like, you can find Luke at the roost. give us a little follow. It would help us out a lot if you use the old Apple Podcasts to leave a review of the show because that's what helps other people to find it. So thanks again, everybody. I hope you have a wonderful night.
|
||||||
@@ -0,0 +1,427 @@
|
|||||||
|
LUKE: All right, welcome back, ladies and gentlemen. I'm Luke. This is Luke at the Roost, the call-in radio show, where you can call in and talk to me about what's going on in your life, and I'll give you the best advice I can. If you'd like to call in, our number is 208-439-58-3. That's 208-439 Luke. It is Thursday, February 26th, and we're going to get to to the phones right away today. We've got Cedric on the line. Cedric, what's going on? How can we help you today?
|
||||||
|
|
||||||
|
CEDRIC: Hey, Luke. Yeah, uh, thanks for taking the call. I've been listening for a while. Figured I, I don't know, maybe you can help me think through something. So I've got this situation with my gym. I've been going to the same place for like two years now. Same personal trainer. We've got a good routine going.
|
||||||
|
|
||||||
|
LUKE: Okay, what's the problem with your gym?
|
||||||
|
|
||||||
|
CEDRIC: go, I ran into him at the Safeway, my trainer.
|
||||||
|
|
||||||
|
LUKE: Okay, is this a problem with your gym or a problem with your trainer? I think I know where this is going.
|
||||||
|
|
||||||
|
CEDRIC: Yeah, it's, okay, so we got beers. Just ran into each other. He was grabbing groceries. I was grabbing groceries, and he asked if I wanted to grab a beer, and I said, yeah. And then we ended up sleeping together.
|
||||||
|
|
||||||
|
LUKE: In the safe way?
|
||||||
|
|
||||||
|
CEDRIC: Yeah, yeah, safe. But now, now I've still got sessions with him twice a week. Tuesdays and Thursdays, and I've already paid through March. And it's like...
|
||||||
|
|
||||||
|
LUKE: It's like what? I mean, you slept with your personal trainer. Could you be more cliche?
|
||||||
|
|
||||||
|
CEDRIC: I know. I know. But it's really awkward now. Like neither of us is saying anything about it, but when he's spotting me or doing assisted stretches, we're both just... We're so aware of where hands are going, you know? And I'm married.
|
||||||
|
|
||||||
|
LUKE: So you cheated on your wife with your male personal trainer at the same thing?
|
||||||
|
|
||||||
|
CEDRIC: safe way. Well, not at the safe way. After. But yeah, and my wife and I, we got married young, like 22 high school sweethearts, and we're still kind of...
|
||||||
|
|
||||||
|
LUKE: You're still kind of what?
|
||||||
|
|
||||||
|
CEDRIC: We're still figuring out what the rules are, I guess. Like what counts? Whether this even matters if it was just once. I haven't told her yet.
|
||||||
|
|
||||||
|
LUKE: Yeah, I think it matters. You cheated on your wife with a dude. She's probably not going to be happy about that.
|
||||||
|
|
||||||
|
CEDRIC: I know. I know she won't be. But also, like, I keep thinking about the logistics of it.
|
||||||
|
|
||||||
|
LUKE: The logistics of what?
|
||||||
|
|
||||||
|
CEDRIC: The gym situation. The contract. The fact that Sierra Vista is too small to just disappear.
|
||||||
|
|
||||||
|
LUKE: Well, yeah, you can't disappear. Do you have feelings for this trainer dude? More so than the wife that you married?
|
||||||
|
|
||||||
|
CEDRIC: No. I mean, I don't know. It wasn't like that. We just ran into each other at Safeway. Got beers. And then it just kind of happened.
|
||||||
|
|
||||||
|
LUKE: You just went to a grocery store and fell into his asshole? Like, I don't understand how that just happened. You just happened to have sex with a guy at the grocery store? Like, what are you talking about? It just happened. That was a conscious decision that you both had to make. Like, you had to figure out where you were going to go and how you were going to do it. It wasn't like a spur of the moment situation. You left a store to go somewhere else to have sex.
|
||||||
|
|
||||||
|
CEDRIC: You're right. Okay. Yeah. We went back to his... place, it wasn't just, it didn't just happen.
|
||||||
|
|
||||||
|
LUKE: All right, so what's the deal? You're going to tell your wife about this and how's she going to react?
|
||||||
|
|
||||||
|
CEDRIC: I don't know if I'm going to tell her. That's kind of why I called, because I keep going to these sessions on Tuesdays and Thursdays, and we just don't talk about it. We do the stretches, and he spots me, and neither of us says anything, but we both know. And I've got the contract through March, and I already paid, and there's nowhere else to go in town.
|
||||||
|
|
||||||
|
LUKE: Well, here's my advice. because not telling your wife is a rotten thing to do. And deal with the fallout of that. And if you, if things are weird with your personal trainer and things are weird with your wife, which they will be, eat the money. And just don't go. You don't need a personal trainer. You can, you know how to do your, your fucking deadlifts.
|
||||||
|
|
||||||
|
CEDRIC: Yeah, you're right. I just, I keep thinking if I can just get through March without making it weird, then the contract's up and I can just let it expire. And nobody has to know, and it goes away.
|
||||||
|
|
||||||
|
LUKE: You'll know. He'll know. And it won't go away. It'll haunt you for the rest of your life because you'll be keeping this massive secret from your betrothed.
|
||||||
|
|
||||||
|
CEDRIC: I know. I know you're right. It's just we've been together since high school, since we were 17. And I don't even know if this means something about me or if it was just a one-time thing or what it was.
|
||||||
|
|
||||||
|
LUKE: Well, it means a few things about you. It means you're into dudes, obviously. I don't know if you knew that or not. but if you have sex with a guy, you're into dudes. And it means you're a liar because you cheated on your wife without telling her and having that conversation first.
|
||||||
|
|
||||||
|
CEDRIC: I mean, I don't know if I'm into dudes. It was just him. I've never thought about that before.
|
||||||
|
|
||||||
|
LUKE: Okay, well, he is a dude, and you're into him, which would, by definition, mean you're into dudes.
|
||||||
|
|
||||||
|
CEDRIC: Yeah, okay. Yeah, you're right. I just, I don't know what I'm supposed to do with that. Like, do I tell her?
|
||||||
|
|
||||||
|
LUKE: that part too?
|
||||||
|
|
||||||
|
CEDRIC: Yeah, I would think so. I mean, the alternative is you're like, you know what? I'm not even into dudes. I just didn't want to have sex with you so badly that I had sex with him anyway, even though I don't like the male sex.
|
||||||
|
|
||||||
|
LUKE: God, when you put it like that, I just, we got married so young. And I don't think either of us really knew what we were doing. And she's a good person.
|
||||||
|
|
||||||
|
CEDRIC: Okay, well, do you still want to be married?
|
||||||
|
|
||||||
|
LUKE: I don't know. I mean, yeah? She's my best friend. We have a whole life.
|
||||||
|
|
||||||
|
CEDRIC: Yeah, that doesn't sound very convincing, and it sounds like maybe you're undercutting her here, and that's not very fair.
|
||||||
|
|
||||||
|
LUKE: No, you're right. I'm being a coward about this whole thing. I think I'm more worried about what happens after. Like, what do I even do in Sierra Vista if we split up? Everyone knows us together.
|
||||||
|
|
||||||
|
CEDRIC: You move on with your life, and people forget, and who cares what everybody else knows? If you don't want to be married, then don't be married, but don't string her along thinking that you're all in love and shit and then be out fucking dudes on the side. That's not cool.
|
||||||
|
|
||||||
|
LUKE: You're right. That's not fair to her. I need to tell her everything. The whole thing. Not just that it happened, but...
|
||||||
|
|
||||||
|
CEDRIC: Well, I don't know the woman, so, I mean, talk to her and let her know what happened and how you're feeling and see if that's something that you two can navigate if you want to stay together. Otherwise, let her off the hook, because what you're doing isn't right or fair to her. If you want to go off and you got married too young and you're not sure about it and you want to experiment and, you know, sow your wild oats or whatever, then do that, but let her go.
|
||||||
|
|
||||||
|
LUKE: Yeah, I know. I'm going to talk to her this weekend. Just lay it all out.
|
||||||
|
|
||||||
|
CEDRIC: All right, buddy. Good luck to you. I hope that goes all right. And don't do that stuff. Don't cheat on your spouse. It's not cool. We have Shonda. Shonda, thanks for calling in. What's going on in your life today?
|
||||||
|
|
||||||
|
SHONDA: Hey, Luke. Thanks for taking my call. So, I got accidentally C-Ced on an email today, where my friends are planning an intervention for me this Saturday because they think I'm spiraling. But honestly, I think they're overreacting. And I just wanted to talk to someone who might actually listen before they all show up at my apartment.
|
||||||
|
|
||||||
|
LUKE: Okay. Do you think your friends think you're spiraling?
|
||||||
|
|
||||||
|
SHONDA: Well, I have been watching a lot of body cam footage lately. Like police body cam videos, dash cam stuff. And I guess I have missed a couple brunches because I was up until three in the morning watching them. So I was too tired.
|
||||||
|
|
||||||
|
LUKE: So they're going to have an intervention because you missed brunch because you are up late watching body cam footage?
|
||||||
|
|
||||||
|
SHONDA: Yeah. When you say it like that, it does sound kind of silly.
|
||||||
|
|
||||||
|
SHONDA: But I think they're also worried because I've been staying late at work a lot to avoid going home. And I guess I've been talking about it maybe more than they want to hear about it. Like, I find it really fascinating how people behave under pressure, you know, in these high-stress situations.
|
||||||
|
|
||||||
|
LUKE: Why are you avoiding going home after work? What's going on at home?
|
||||||
|
|
||||||
|
SHONDA: Oh gosh. Well, nothing terrible. I live alone. It's just kind of quiet and empty. And when I get home, I end up just opening my laptop and going down these rabbit holes. At work, I can at least have the body cam stuff on one side of my screen and my spreadsheets on the other, so I feel like I'm being productive. At home, it's just me and the videos. And suddenly, it's three in the morning and I haven't eaten dinner.
|
||||||
|
|
||||||
|
LUKE: Well, that is a strange thing. I mean, I know a lot of people have their rabbit holes that they go down into true crime and pimple popping or cake baking, whatever it might be. So it's not that weird that you found a thing that interests you and keeps your mind occupied, but if it's affecting your eating and your social life, that's a problem.
|
||||||
|
|
||||||
|
SHONDA: You're right. I know you're right. I just feel like they're making it into this big scary thing. When really, I just got interested in something. Like, my friend Sarah sent this whole paragraph in the email about how I used to be so bubbly, and now I seem distant. And I'm like, I'm the same person. I just have a new interest. But yeah, the not eating thing, that's probably not great.
|
||||||
|
|
||||||
|
LUKE: What is it about the body cam footage that you're finding so compelling? Like you said the high stress situations and people's reactions there, but, I mean, how can that continue to be compelling once you've seen, you know, a day's worth of them?
|
||||||
|
|
||||||
|
SHONDA: That's actually a really good question. I think it's because every single one is different, you know? Like, you'd think after watching 100 traffic stops, they'd all blur together, but they don't. Some people completely fall apart. Some people get really polite and compliant. Some people try to run. Some people just shut down completely. And I keep thinking about what I would do, how I would react, if I was in that situation.
|
||||||
|
|
||||||
|
LUKE: Does it turn you on, the power dynamic?
|
||||||
|
|
||||||
|
SHONDA: What? No. Oh, gosh, no. It's not like that at all. It's more like, I don't know, studying human behavior. Like when you watch those nature documentaries and see how animals react when they're cornered.
|
||||||
|
|
||||||
|
LUKE: I can understand that. And I can understand getting sucked into some kind of compelling true media like that. I mean, I'm sure it's not all even true. A bunch of that stuff is probably staged. But if it's affecting your life and keeping you up at night and you're not eating and you're not socializing with your friends, that's a problem that maybe they're right to be concerned about. So I would listen to them and strongly consider if this is kind of taking over your life more than you wanted to.
|
||||||
|
|
||||||
|
SHONDA: Yeah, you're probably right. I guess when my boss accidentally sent me that email and I saw how worried they all are, Part of me wanted to just prove them wrong, you know? Like show up to the intervention and be like, see, I'm fine. This is just a hobby. But sitting here talking to you about it, saying out loud that I'm not eating dinner and I'm avoiding my own apartment, that does sound like maybe it's gotten a little out of hand. I just hate the idea of them thinking I'm broken or something when I genuinely find this stuff, interesting, and educational.
|
||||||
|
|
||||||
|
LUKE: Well, you don't necessarily have to give it up. It doesn't sound like the media itself is a problem. If you're watching those videos at work and still being productive, you can, you know, have that plan in your ear pods while you're out going for a walk just to make sure you're getting enough sleep, you're eating, and you're taking care of yourself. And I wouldn't be, you said you're avoiding going home to your own apartment because you're just going to stay up all night on this rabbit hole of videos. That's not good, no matter what the videos are.
|
||||||
|
|
||||||
|
SHONDA: You're absolutely right. It's not really about the videos themselves. It's about me using them to avoid other stuff. Like, I could watch this content in a normal way. But instead, I'm staying at my office until 11 at night because I don't want to be alone with my thoughts. And then the videos are just there to fill that space.
|
||||||
|
|
||||||
|
LUKE: And what thoughts are you having that you're trying to get away from? What's going on in your head that you need to numb with the body cam footage?
|
||||||
|
|
||||||
|
SHONDA: Oh, shoot, that's a hard question. I guess, well, my apartment just feels really empty lately. My roommate moved out in December to move in with her boyfriend. And I thought, I'd like having my own place, but it's just quiet all the time. And I keep thinking about how I'm 32, and I don't have that, you know? Like everyone's pairing off, and I'm just coming home to watch videos on my laptop.
|
||||||
|
|
||||||
|
LUKE: Yeah, but that's not the only thing you can do at home. You could come home to make yourself a nice dinner and exercise and, you know, create something, whatever your hobby is. It doesn't have to just be going home to watch content, you could go home and make content, or you could go out and participate in your community. There's a lot of things you could do to occupy your time and fill that space with something more productive. Why aren't you doing those other things?
|
||||||
|
|
||||||
|
SHONDA: Because they all sound exhausting, honestly. Like making a nice dinner for one person? That just feels sad. And I used to paint a little bit. But when I set up my easel in the living room, it just reminded me that there's nobody there to see what I'm making or care if I finish it. I think the body cam videos are easy because they don't require anything from me. I can just watch other people's worst moments and feel like at least my life isn't that bad. At least I'm not getting arrested or having a breakdown on the side of the highway.
|
||||||
|
|
||||||
|
LUKE: No, but you do have your friends staging a literal intervention because they're concerned about your well-being and your health because of your behavior.
|
||||||
|
|
||||||
|
SHONDA: Oh, gosh, yeah, when you put it like that. I guess I am having my own kind of breakdown. Just a slower, quieter one where I'm sitting at my desk instead of on the highway. That's actually kind of worse in a way, isn't it?
|
||||||
|
|
||||||
|
LUKE: I don't know if there's a better or worse kind of breakdown, but it's definitely not healthy that. And I think you should hear your friends out when they stage this intervention because they care about you and they want to make sure that you're in good health. So listen to them. See if maybe they have good suggestions to kind of get you out of this slump. And maybe try to make some decisions, take some actions to pull yourself out of it and do something else. I'm not saying you have to stop watching these videos, that's, I don't think that's a problem. But you do have to participate in life.
|
||||||
|
|
||||||
|
SHONDA: You're right. I think I've been so defensive about it. Because I didn't want to admit that something's actually wrong. Like if I can just insist it's a normal hobby, then I don't have to deal with the loneliness part. But they're staging an intervention because they love me. Not because they think I'm weird. I should probably just go to the thing on Saturday and actually listen instead of trying to prove them wrong.
|
||||||
|
|
||||||
|
LUKE: Yep, that's what I think you should do because, I mean, watching videos isn't much of a hobby. I mean, I'm not going to say one hobby is better than another hobby, but if you're only consuming content, it's hard to even call that a hot. I mean, a hobby is woodworking or painting or singing or creating something of your own, not just consuming something that somebody else has created for you. Even people that are really into movies or music, they're not just listening to music or movies. They're formulating opinions and dissecting the directors and tension and writing essays and stuff.
|
||||||
|
|
||||||
|
LUKE: So even those types of hobbies still have a creation component, whereas what you're describing is not that at all. That's a really good point.
|
||||||
|
|
||||||
|
CALLER: I'm not even engaging with it critically. I'm just letting it wash over me. Like, I'm not learning anything about criminal justice or police procedures or even human psychology, really. I'm just numbing out. And I used to actually make things. I painted. I used to write these little essays about art exhibits I'd see. I stopped doing all of that, and I didn't even notice when it happened. I just gradually replaced creating with consuming until my whole life became about filling time instead of doing something with it.
|
||||||
|
|
||||||
|
LUKE: Okay, well, it sounds like you have a plan. You're going to hear out your friends at their intervention. I'm not saying take all their advice, but be open to some of it because they may have good ideas. And I would suggest that you take some steps to move back into creating something or participating in life. And don't just put yourself to sleep with videos every night because that's a sad way to exist. And you probably can get more out of life than that.
|
||||||
|
|
||||||
|
CALLER: You're absolutely right, Luke. Thank you for being honest with me instead of just letting me justify it. I think I needed someone outside my friend group to tell me the same thing they've been trying to say. I'm going to go to the intervention on Saturday with an open mind, and maybe this weekend I'll pull my easel back out.
|
||||||
|
|
||||||
|
LUKE: Okay, I wish you the best of luck, and hopefully you don't end up on the wrong side of one of those body cam videos. And ladies and gentlemen, it is time. It's that time again for a word from our sponsors. This episode is brought to you by Desert Gut, the all-in-one nutritional supplement made from things you'd actually find within walking distance from my RV. Each scoop of Desert Gut contains 17 adaptogens, nine minerals scraped, directly off a rock, pulverized tumbleweed fiber, and a proprietary blend we're calling coyote dust, which our lawyers have asked me to clarify as not made from actual coyotes. Desert gut tastes like someone described the color beige to a blender, but you'll feel incredible or you'll feel something. First five callers get a free shaker bottle that definitely used to be a gas station coffee cup. Desert gut, because your gut isn't going to desert itself. All right, we're back here. And let's, uh, let's get back to the phones. First up, we've got Phil. Phil, welcome back to the show. You're a returning caller. What, uh, what can we do for you tonight?
|
||||||
|
|
||||||
|
PHIL: Hey, Luke. Yeah, thanks for taking my call again. So, uh, remember last time I called, I was kind of freaking out about the whole situation with my wife, Teresa, and this open marriage thing we were trying. Well, fast forward to last week, Marcus and I, we have been seeing each other pretty regularly, then. Nothing serious, just dinners, and we have been taking it slow. And Teresa has been with her girlfriend Amanda. Everything seemed like it was working out the way we talked about. But then Sunday night, Marcus tells me he is moving.
|
||||||
|
|
||||||
|
LUKE: Oh, okay. So now how are you feeling now that your wife has something on the side and yours is taken off? Do you feel left out?
|
||||||
|
|
||||||
|
PHIL: No, it is not even that, really. I mean, yeah, maybe a little bit. But the thing that got me was how I reacted when he told me. We were sitting in his truck outside this diner over in Scotland. And he is telling me about this job offer in Portland. Really good opportunity for him. And I just, I nearly lost it. Like I felt this panic in my chest that I have not felt in years. And I realized I was way more attached to this guy than I thought I was. And here is the thing that is messing with me.
|
||||||
|
|
||||||
|
LUKE: What's messing with you? This whole situation is a little bit interesting. It's unique.
|
||||||
|
|
||||||
|
PHIL: What is messing with me is that I went home that night. And I could not even look at Teresa, because I realized I have been lying to myself this whole time. I thought I was doing this open thing to make her happy, to keep our family together. Be the good guy, you know? But sitting in that truck with Marcus, feeling like my heart was being ripped out because he is leaving, I realized I actually have feelings for him, real feelings. The kind I have not had for Teresa in, I do not even know how long.
|
||||||
|
|
||||||
|
LUKE: Yeah, but you said that last time, too, you said you two had kind of a platonic relationship, but you were good partners and wanted to stay married for the other benefits of marriage sort of homosexual things on the side.
|
||||||
|
|
||||||
|
PHIL: Yeah, I know I said that, but I think I was still trying to convince myself that was enough, you know? Like, I could compartmentalize it. Marcus over here in this box. Teresa and our life together in that box. And everybody gets what they need. But when he said he was leaving, it was not just like losing a friend or even just a hookup.
|
||||||
|
|
||||||
|
LUKE: Yeah, this dude broke your heart while you're married to this other woman who's flourishing with her girlfriend. It's a strange situation to be in, but you did kind of put yourself there.
|
||||||
|
|
||||||
|
PHIL: You are right. And that is what I have been sitting with all week. I put myself here. I agreed to this whole thing thinking I was being evolved or whatever. But really, I was just avoiding the harder conversation. Because now I am looking at Teresa and she is happy. Like, genuinely happy in a way I have not seen her in years. She's texting Amanda all the time, smiling at her phone. And I am over here heartbroken over a guy I have been seeing for two months.
|
||||||
|
|
||||||
|
LUKE: So what are you going to do about it? Are you going to continue your marriage with Teresa? I mean, I wouldn't say it's a sham marriage. You do say that you're good partners and you've got, you know, the other life stuff together entwined and that's working out well. Do you want to end your marriage with Teresa and move into your new gay lifestyle?
|
||||||
|
|
||||||
|
PHIL: That is the question I have been avoiding all week. And honestly, I do not know. Part of me thinks, okay, Marcus is leaving. This will pass. I will meet someone else eventually. Keep the arrangement with Teresa. But then I think about my uncle, Hector.
|
||||||
|
|
||||||
|
LUKE: Right.
|
||||||
|
|
||||||
|
PHIL: He stayed in a marriage for 30 years. That was not really a marriage, just because it was easier than admitting what he actually wanted.
|
||||||
|
|
||||||
|
LUKE: Well, you know, if you've had enough a marriage and you're not into that and you don't see yourself continue in this arrangement for the long term, then talk to Teresa and end the marriage. Because it seems like, you know, she's got her own thing going on. You've got to figure out what it is that you want out of life.
|
||||||
|
|
||||||
|
PHIL: Yeah, but here is what really gets me. I called you last time because I was freaking out about the arrangement. And you helped me calm down, realize I did not need to have it all figured out right away. And that was good advice. But now I am wondering if I use that as an excuse to just keep avoiding the real thing, which is that I do not think I want to be married anymore.
|
||||||
|
|
||||||
|
LUKE: That's okay. That's what divorce is for. So, I mean, it sounds like you can talk to Teresa and end that marriage amicably and move on to whatever it is you want to move on to.
|
||||||
|
|
||||||
|
PHIL: You make it sound so simple. And maybe it is. I mean, we do not have kids. The house is in both our names, but we could figure that out. She has her job. I have mine. It is not like 20 years ago when we were broke college kids who needed each other just to survive. But then I think about telling my Uncle Hector that I am getting divorced. And I already know what he is going to say.
|
||||||
|
|
||||||
|
LUKE: It doesn't really matter what your uncle has to say. And I'm saying it, uh, simply because you're not coming at this from a place of hurt or anger. You both have already talked this through. You have a unique agreement. And I think if you bring this up and just explain that, hey, this isn't really working for me. I don't want to be married. I think that you can end that on a, maybe not a positive note, but not a negative one.
|
||||||
|
|
||||||
|
PHIL: You know what, you are right.
|
||||||
|
|
||||||
|
LUKE: Next up, we've got Marlene. Marlene, welcome to the show. What's going on in your life? Do you have a homosexual lover that you're conflicted about? Is that what's going on? It seems to be everybody's call today.
|
||||||
|
|
||||||
|
MARLENE: No, nothing like that. I went to my manager's holiday party dressed as a full banana, and now I have a disciplinary meeting in the morning.
|
||||||
|
|
||||||
|
LUKE: Okay, why did you do such a thing?
|
||||||
|
|
||||||
|
MARLENE: The invite said costume party. Big letters at the top. So I rented the whole setup, phone body, the stem on top, professional grade, showed up. and everyone's in sweaters, drinking wine, spritters, talking about their time shares?
|
||||||
|
|
||||||
|
LUKE: All right, so it was a costume party. You wore a costume. What's the discipline there? What else happened that would get you called into the manager's office?
|
||||||
|
|
||||||
|
MARLENE: Nothing happened. I just stayed. All four hours. Talk to Janet from accounting about her divorce while I'm standing there like a piece of fruit.
|
||||||
|
|
||||||
|
LUKE: It sounds like an interesting party. I wouldn't worry about it too much because it doesn't sound like you did anything wrong. Might be a little embarrassed that you were the only one that I don't know that there's any reason for discipline there.
|
||||||
|
|
||||||
|
MARLENE: That's what I thought. But apparently showing up in a banana costume to discuss quarterly performance metrics demonstrates lack of professional judgment. Direct quote from the email. Meetings at nine tomorrow morning with my manager and someone from corporate HR.
|
||||||
|
|
||||||
|
LUKE: I think you just need to explain that it was a misunderstanding. Because if you were going to a costume party, it wasn't to discuss quarterly performance metrics. So you were called to that party under false pretenses. of the purpose of the party.
|
||||||
|
|
||||||
|
MARLENE: See, that's the thing though. The endbot had both. Top half said costume party. Bottom half had the agenda with all the work stuff. I've just figured we'd do the boring part fast and then actually party. But no, four hours of standing next to the veggie tray and full banana while Greg from IT pitched his fantasy football league.
|
||||||
|
|
||||||
|
LUKE: I don't think you have to worry about it. Just explain that you didn't understand the instructions because that's not clear. Said costume party, you wore a costume, it wasn't an offensive costume, and it's a costume. It doesn't sound like you did anything to deserve discipline. So it sounds like maybe a formality they got to do, or maybe somebody just doesn't like you.
|
||||||
|
|
||||||
|
MARLENE: Yeah, maybe? I heard Cedric earlier talking about his trainer situation, and I kept thinking, at least I'm not hiding who I sleep with from my wife. I just showed up to a party wrong. His whole marriage is built on not telling the truth. Makes my banana thing seem pretty small.
|
||||||
|
|
||||||
|
LUKE: Well, we all have small bananas here at Luke of the Roost, so that's understandable. I wouldn't worry about it. I think you sound like a fun person. You followed the instructions. You wore your costume in all good faith and tried to participate in what you thought was a costume party. That went wrong and if they want to give you a hard time about it, fuck them. That's what I say.
|
||||||
|
|
||||||
|
MARLENE: I appreciate that. The worst part is the makeup still will not come off my neck. I scrubbed it in the bathroom here twice already. Going to show up to the disciplinary meaning tomorrow with a yellow ring around my collar. like I've got jaundice or something. They are going to think I'm committed to making this worse.
|
||||||
|
|
||||||
|
LUKE: You know what you should do. You should go to that disciplinary meeting dressed full banana.
|
||||||
|
|
||||||
|
MARLENE: You know what? I actually considered keeping the costume in my truck for exactly that reason. Just walk in there, sit down across from corporate, let them say their piece while I'm foam and yellow from head to toe. But I already pulled a stranger's truck out of a wash during monsoon season and did not even get a thank you, so I know how these things go. Nobody appreciates the commitment.
|
||||||
|
|
||||||
|
LUKE: I appreciate the commitment. So if you do decide to go in there at full banana, we'd like to see a video. Send the video to submissions at look at the roost.com, and we'll make sure that the Luke at the roost army gets a good look at it. And you'll be a hero to us all.
|
||||||
|
|
||||||
|
MARLENE: All right, I'll think about it. Worst case, I've already got the costume and nothing left to lose except a third shift human resources job at a call center. If they fire me over a banana suit, that is a story I can tell for the rest of my life. anyway.
|
||||||
|
|
||||||
|
LUKE: That's right. If they fire you over a banana suit, you deserve a better job. That's what I say.
|
||||||
|
|
||||||
|
MARLENE: You're probably right. I've been doing this job for three years and the highlight was still tonight standing in that break room as a banana. That should tell me something.
|
||||||
|
|
||||||
|
LUKE: All right. Thanks for the call. And you make me very proud. Very, very proud. Thanks, Marlene. I hope everything works out for you in your disciplinary meeting tomorrow. Next up, we've got Dary. Daryl. Welcome to the show. How are you doing today, sir?
|
||||||
|
|
||||||
|
DARNELL: It's Darnell, but I'm all right. Being better.
|
||||||
|
|
||||||
|
LUKE: Oh, I'm sorry. I read your name wrong. What's going on? What's up, Darnell?
|
||||||
|
|
||||||
|
DARNELL: Darnell. My girlfriend took the $3,200 we saved for our vacation and lost it at the casino. Found out about three hours ago.
|
||||||
|
|
||||||
|
LUKE: Uh-oh. Has that kind of thing happened before?
|
||||||
|
|
||||||
|
DARNELL: Not like this.
|
||||||
|
|
||||||
|
LUKE: So, I mean, I think a lot of us have been in that situation before. You get a little kind of scratch happy with the old lottery tickets and the blinky lights and sounds from the casino. It's easy to get a little bit carried away. But I think once something like that starts, it's kind of, It's hard to get over. Have you talked to her about it? Did she apologize or does it seem like she's going to continue down this road?
|
||||||
|
|
||||||
|
DARNELL: She apologized, cried for about an hour before I got home from work. But here's the thing. She's been hiding it for weeks. Three separate trips. That's not getting carried away one time. That's a pattern.
|
||||||
|
|
||||||
|
LUKE: That is a pattern and that is an addiction. And it's a sad thing and it happens to a lot of people. And you have to decide if you want to be there to support her through it. Maybe you do and maybe you don't. That's up to you. What are you thinking?
|
||||||
|
|
||||||
|
DARNELL: I locked myself in the bathroom with a shower running so I could call you instead of talking to her.
|
||||||
|
|
||||||
|
LUKE: That probably answers your question. No, it doesn't really because this just happened and you're heard about the lying and you heard about the money and you're heard about the vacation and it's so new that you're probably not thinking super clearly. It's going to take a little bit of time for you to calm down and digest that and determine what it is you want to do to move forward.
|
||||||
|
|
||||||
|
DARNELL: We've been together four years. I work 10 hour days doing roofs in the sun. She works at the credit union. We split everything 50-50. We don't fight about money. We had a plan. And now I'm sitting here on a toilet at 11.30 at night because I don't know what to say to her.
|
||||||
|
|
||||||
|
LUKE: Well, you know, she spent the big vacation fund. It's not like she remortgaged the house out from under you. So that's a bummer if you can't go on vacation this year because that happened. But I think you need to take some time and consider your four-year relationship and see if this is enough to break it.
|
||||||
|
|
||||||
|
DARNELL: She lied to me for three weeks, told me she was at her sisters. I called her sister two weeks to ask about borrowing their cooler. And her sister had no idea what I was talking about. I didn't think anything of it then.
|
||||||
|
|
||||||
|
LUKE: Yeah, it's a bummer. She lied to you. That's what addicts do. And she was going off to the casino and trying to get the money back so that she didn't have to admit it. That's an understandable thought process for an addict.
|
||||||
|
|
||||||
|
DARNELL: So what? I'm supposed to just understand it. We were leaving for Cabo in three weeks. I already requested the time off. My boss gave me grief about it because we're in the middle of a job.
|
||||||
|
|
||||||
|
LUKE: Well, you have to decide if it's something that you want to understand because if you love the woman and she's got this sickness, then maybe you want to help her out and help her, you know, find ways to overcome it in the future. And if you don't, if it's too much, I mean, if it's broken your trust in her irrevocably, then maybe it's time to break up.
|
||||||
|
|
||||||
|
DARNELL: I heard Phil earlier, the guy with the open marriage who caught feelings for Marcus. You told him he was lying to himself about wanting to stay married. You didn't give him the maybe you can work through it speech.
|
||||||
|
|
||||||
|
LUKE: No, I did not tell him that he was lying to himself. He told us that he was lying to himself. And I just allowed him to go with what he already knew deep in his heart. You have not given us that context. So I don't know what your relationship is. If you don't want to be with this woman anymore, then this is a great excuse to not be with her anymore. But if you love the woman and you want to ending issue. Maybe you can't go to Cabo this year. So sad. That's a bummer. But, but, you know, you can help her get to meetings or support groups or find a way to overcome that compulsion to gamble and make sure she doesn't lie to you again.
|
||||||
|
|
||||||
|
DARNELL: I'm sitting in a bathroom with the shower running because I can't look at her right now. That should tell you something.
|
||||||
|
|
||||||
|
LUKE: It does. It tells me you're angry because you were just wronged and that makes sense. That's not telling me how you're going to feel about it a week from now.
|
||||||
|
|
||||||
|
DARNELL: A week from now, I'm still going to be the guy who works 10 hours in the sun while she sits in air conditioning and blows our money at the casino. That's not going to change.
|
||||||
|
|
||||||
|
LUKE: All right. Well, if you can't get over it, then maybe it's time to move on and let her know that, sorry, I can't take the lying. And you've broken my trust and I no longer want to be with you. You can, I mean, it's not on me to tell you what to do in your relationship. I'm just trying to give you the best advice I can. And my advice for you is to give it some time so that you can cool down and think about it clearly.
|
||||||
|
|
||||||
|
DARNELL: I already know what I'm going to do. I needed to hear someone say it out loud, so it didn't just stay in my head. I'm not leaving her over $3,200. I'm leaving her because when I found out, my first thought was relief.
|
||||||
|
|
||||||
|
LUKE: All right then. It's time to leave the woman. And good luck to you your future endeavors and good luck to her. Hopefully that she finds the help that she needs and doesn't end up destitute from gambling everything away.
|
||||||
|
|
||||||
|
DARNELL: Yeah. Thanks for taking the call.
|
||||||
|
|
||||||
|
LUKE: Best of luck to you both. Okay, I think it's about time we're obligated to play another ad here from our sponsors. Let's get this music stopped. I'm going to get dark for a second. You're going to die someday. Not today, probably, but someday. And when you do, what's going to represent your business? A Craigslist post from 2020? A Google Maps pin that still says permanently closed because you forgot to update it after COVID. A nephew who knows computers but actually just has a Reddit account? Your legacy deserves better than a Reddit account nephew with a Reddit account. Squarehole lets you build something that outlasts you. Something your kids can point to and say, Dad built that. They won't know it took you 11 minutes. That's between you and Squarehole. And when your nephew says, I could have built that for you for free, you can look them in the eye and say, then why didn't you, Tyler? I asked you in 2021 and you said you were busy and you were not busy. Squarehole. Build it before Tyler has to, because Tyler is not Not going to. All right. Thanks to Squarehole. If you need a website, Squarehole is the place to go. All right, let's see. Next up on the old line, we have Val. Val, welcome to the show. How can we help you tonight?
|
||||||
|
|
||||||
|
VAL: Hey, Luke. Yeah. So, my dog died yesterday morning, and I don't really know what to do with myself. Cisco, he was 14. He just didn't wake up.
|
||||||
|
|
||||||
|
LUKE: Oh, I'm sorry. That's the worst. That's the worst day in any pet owner's life. It's the hardest thing to lose a pet. So I feel for you.
|
||||||
|
|
||||||
|
VAL: Yeah. Thank you. I mean, I knew it was coming. You know, he was old. But it still just knocked me flat. I called in sick to work tonight, but then I came in anyway because I couldn't stand being in the house. Just sitting here doing paperwork because the quiet at home is too much.
|
||||||
|
|
||||||
|
LUKE: Yeah, I understand it a few times and it does tear you up inside and there's really not much you can do to get over it. And then you come home and you see his bowl and you see his toys and it's just, it's a very sad time. But you can hold on to the life that you gave him and remember the happy times and that he loved you and try to remember him when he was having fun and enjoying life.
|
||||||
|
|
||||||
|
VAL: and he had this thing where he'd sleep with his head on my feet every night. So last night, I'm in bed, and my feet are just cold, and I kept waking up expecting the weight to be there. My boyfriend Rick is out on a job in Lordsburg until Saturday. So it's just me and all of Cisco stuff everywhere.
|
||||||
|
|
||||||
|
LUKE: Well, I would recommend when you go home today, you pick all that stuff up and put it somewhere. You're not going to have to see it.
|
||||||
|
|
||||||
|
GREG: Hey, Luke, thanks for taking my call. So three nights ago, someone stood on my front porch at three in the morning for almost 11 minutes straight and never took a breath. I have it on video.
|
||||||
|
|
||||||
|
LUKE: What do you mean, never took a breath? Like held his breath?
|
||||||
|
|
||||||
|
GREG: I mean exactly that. I have doorbell camera footage, ring, the newer model with the enhanced night vision, and I have scrubbed through it frame by frame. This person is standing there from 317 a.m. to 327 and 43 seconds a.m. facing my door and their chest never moves, not once.
|
||||||
|
|
||||||
|
LUKE: Well, that's a weird thing. Just a stranger shows up on your porch, holds his breath and then leaves?
|
||||||
|
|
||||||
|
GREG: Well, that's the thing. They didn't just show up. They were such a and leave there. The motion sensor light should have triggered when they approached. According to the manufacturer's specs, it activates at 15 feet, but it never turned on. They're just there in frame one second, standing maybe four feet from my door, and then, after the 10 minutes, 43 seconds, next frame they're gone. No walking away, no turning around.
|
||||||
|
|
||||||
|
LUKE: What do you think that's about? Do you think that's a ghost or a demon or a zombie?
|
||||||
|
|
||||||
|
GREG: I don't know what I think. That's why I'm calling. I've been down every forum, every paranormal subreddit, missing persons reports for Hidalgo County going back five years. I even cross-reference the timestamp with local police logs. Nothing reported that night in my neighborhood. But here's what really gets me. I measured it. The figure is approximately 5'7, wearing what looks like a dark hoodie, and in frame 206, if you zoom in on the pixel density around the edges, There's this weird distortion that shouldn't be there with that camera model under those lighting conditions.
|
||||||
|
|
||||||
|
LUKE: What kind of a distortion? Like an aura? Like a movement? Do you think it was a vampire that was waiting for you to invite him in?
|
||||||
|
|
||||||
|
GREG: Not an aura exactly. More like the kind of digital artifacting you get when there's electromagnetic interference. But localized just around the figure. And okay, I know how the vampire thing sounds, but I actually look at looked into that too. The invitation threshold, mythology, appears in multiple cultures, not just European folklore. Slavic traditions, some Asian variants, but here's what doesn't fit that pattern. This happened on a Tuesday night.
|
||||||
|
|
||||||
|
LUKE: Vampires don't like Tuesdays?
|
||||||
|
|
||||||
|
GREG: Well, actually, in most vampire folklore, there's no specific day restriction, but supernatural transitions. 3 a.m. is considered the inverse of 3pm, the so-called witching hour, though that term is actually a modern invention. The historical devil's hour was midnight. But 317 specifically doesn't correlate with any traditional supernatural timing I could find, which makes me think this might not be folklore at all. It might be something else.
|
||||||
|
|
||||||
|
LUKE: So you still have this video and have you shown it to anybody else?
|
||||||
|
|
||||||
|
GREG: I showed it to Denise, the woman I've been seeing. She keeps a toothbrush at my place though we haven't really defined what we are. And she said, I'm overthinking it. She thinks it's probably just a drunk person or someone on drugs who wandered up, zoned out, then left. But that doesn't explain the motion sensor failure or the lack of respiratory movement. I posted a 10 second clip on one of the forums, no identifying information, and got maybe 30 responses. Half said it's clearly a technical glitch. The other half said, I should sage my house and put salt at the thresholds.
|
||||||
|
|
||||||
|
LUKE: One guy claimed he had something similar happen in Tucson in 2019. Same standing pattern, same duration, but his footage corrupted the next day. Well, have you made any copies of the footage? I think that would be the first step is to make sure that you've got backup footage and maybe on different types of media. So if you could get that on tape, as well as a bunch of different digital containers, an MP4, an MLV file uploaded to YouTube. You know, get it around so it can't be corrupted.
|
||||||
|
|
||||||
|
GREG: I've already done that, actually. Three separate cloud backups. Google Drive, Dropbox, and a private server my buddy runs out of his apartment in McAllen. Plus, I burned it to two DVDs and have the original still on the doorbell's internal storage, which according to the ring documentation, contains files for 60 days before auto deletion. I even exported individual frames as PNG files numbered sequentially. The file integrity checks out on all copies, SH, 2. 5-6 hash is identical across all versions. So if it's going to corrupt, it hasn't yet.
|
||||||
|
|
||||||
|
LUKE: Well, that's an interesting thing. Have you showed it to the authorities at all? Bring it to the police and say that this weird figure showed up on my nest cam or my ring doorbell or whatever the hell it is?
|
||||||
|
|
||||||
|
GREG: No, I haven't gone to the police, and that's actually part of what's been keeping me up. Because what do I say, someone stood on my porch for 10 minutes and then left? That's not a crime.
|
||||||
|
|
||||||
|
LUKE: Well, it kind of is. That's trespassing and it could be considered harassment.
|
||||||
|
|
||||||
|
GREG: That's technically true, but my porch is maybe eight feet from the public sidewalk, and there's no gate or fence. The property line is ambiguous enough that a decent lawyer could argue they never actually crossed onto private property. Plus, Hidalgo County Sheriff's Department is already stretched in with actual crimes. I looked at their call logs, public record, and they're dealing with smuggling cartel activity near the border domestic situations.
|
||||||
|
|
||||||
|
LUKE: Well, I'll tell you what. We'll throw this one out on the Luke at the Roos Discord, so if any of our listeners have any information about this sort of paranormal activity. you can discuss it there and maybe get to the bottom of what this is. I don't know that there's anything you need to worry about. It is concerning and it's definitely non-standard, but it sounds like you've done everything you could do to protect the footage and ask around to people who might know something about it.
|
||||||
|
|
||||||
|
GREG: I appreciate that, though I should mention, and this is what really bothers me. I went back through two months of prior footage and there are three other instances I initially missed. Same figure, same posture, but shorter durations. November 18th at 241 a.m. for three minutes, December 9th at 113 a.m. for 90 seconds.
|
||||||
|
|
||||||
|
LUKE: And did, do they have any identifying features? Does he have a face? Are they not breathing in all of the clips? Anything? It seems weird that a ghost or a vampire would be wearing a hoodie. Is there anything else about the figure that you can identify?
|
||||||
|
|
||||||
|
GREG: That's the thing. The resolution isn't great at night, even with the infrared. It's definitely humanoid, average height, maybe 58 to 510, based on the door frame reference. Dark clothing, possibly a hoodie, like you said, but the fabric doesn't move.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like you, my friend, need a porch light, so that's what I would do first thing, is get a light out there. So if it happens again, you can have some illumination and see what's going on.
|
||||||
|
|
||||||
|
GREG: I have a motion sensor light. That's what I mentioned earlier. It never triggered. The ring specs say it activates for anything over 40 pounds within 12 feet.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, I'm not talking about a motion sensor light. I'm talking about just a regular light that's on all the time so that you don't have to worry about any sort of technical malfunction.
|
||||||
|
|
||||||
|
GREG: That's actually a good point. A constant light source would eliminate the variable of sensor failure. I could install a dusk to dawn LED fixture. They're energy efficient, maybe 12 watts, cost about $1.50 a month to run continuously. That would also give the ring camera better visibility for facial recognition if it happens again.
|
||||||
|
|
||||||
|
LUKE: Yes, sir. I mean, $1.50 a month is probably worth it if you get a ghost showing up on your doorstep, and especially if it's a malicious one and you can save yourself A lot of trouble by scaring him away with the daylight. All right, next up we've got Bernadette. Bernadette, welcome to the show. What's going on out there? Any ghosts on your porch?
|
||||||
|
|
||||||
|
BERNADETTE: And no, nothing like that. I have been watching my neighbors sleep with the mailman for three weeks. And I am trying to figure out if I should tell her husband.
|
||||||
|
|
||||||
|
LUKE: No, you should not tell her husband. It's not your place to tell her husband. Maybe she has already told her husband.
|
||||||
|
|
||||||
|
BERNADETTE: She has not told her husband. He leaves for work at 7.15 every morning. The mail truck shows up at 940, sits there for 20 minutes. She answers the door in different clothes than she wore at drop-off. This happens three times a week.
|
||||||
|
|
||||||
|
LUKE: Well, that's the little thing I like to call none of your business.
|
||||||
|
|
||||||
|
BERNADETTE: I run a home daycare. Their youngest started with me two months ago. I have her kid four days a week.
|
||||||
|
|
||||||
|
LUKE: Yeah, and that has nothing to do with her kids. So, I mean, what are you going to do? Are you going to tell her husband and break up the family? and then ruin that kid's life.
|
||||||
|
|
||||||
|
BERNADETTE: The kid is already in my care while this is happening. I am the one who has to look Christine in the eye at pickup and pretend I do not know she spent her morning with the postal carrier. That feels like my business.
|
||||||
|
|
||||||
|
LUKE: Well, it is not your business. Your business is taking care of that child while she's doing whatever she's doing, which is none of your business.
|
||||||
|
|
||||||
|
BERNADETTE: So I just keep taking her money and smiling at both of them like everything is fine.
|
||||||
|
|
||||||
|
LUKE: That is correct. Yes, everything is fine. It's not a problem for you. It's not a problem for the child. And when the husband finds out, then it might be a problem. But it's not your place to get involved in her life.
|
||||||
|
|
||||||
|
BERNADETTE: Dale waves at me every time he backs out of the driveway. He helped me move my freezer last month. I watch him leave for work every morning. And I know what is about to happen in his house.
|
||||||
|
|
||||||
|
LUKE: It is not your place to tell this man that his wife is cheating on him with the mailman. You can do that. I mean, it's a free country, but I recommend that you don't. And you keep this one to yourself and go about your life because it's not your place.
|
||||||
|
|
||||||
|
BERNADETTE: Fine. I will keep watching the mail truck and saying nothing.
|
||||||
|
|
||||||
|
LUKE: That's a good plan. Good job, Bernadette. Okay, next up on the line we've got Mitch. Mitch, welcome to the show. What's going on?
|
||||||
|
|
||||||
|
MITCH: Hey Luke, thanks for taking my call. So my neighbor's been stealing my water for over a year. I found his hose connected under the fence to my spigot. Been running up my bills this whole time while I'm out here with rocks and cactus trying to keep things And when I confronted him about it yesterday, he just shrugged and said he'd pay me back sometime. Like it was no big deal.
|
||||||
|
|
||||||
|
LUKE: Well, it is a big deal if you've got to pay for the water and he's pulling your water pressure and stuff from the, I assume you have town water or you got a well?
|
||||||
|
|
||||||
|
MITCH: Town water, yeah. And that's the thing, right? Like my bills have been double what they should be. I noticed it, but I just figured maybe there was a leak somewhere or the city was gouging me or something. Didn't occur to me to check if someone was literally siphoning it off.
|
||||||
|
|
||||||
|
LUKE: Well, I would go take pictures of that, the hose leading to his place from your spigot and let the town know and have them come do an investigation.
|
||||||
|
|
||||||
|
MITCH: Yeah, I took pictures already. Got the whole setup documented. But here's what's eating at me, Luke. I went over there yesterday afternoon. kept my cool. Did the whole thing my therapist taught me about staying level? And this guy just looks at me like I'm being unreasonable. Like I'm the it up.
|
||||||
|
|
||||||
|
LUKE: Well, now you're privy to what's going on and you can see how it's affecting your water bill. He's obviously stealing from you and that's costing you money and that's not all right. So you can talk to the police. You can talk to the town or whoever is managing your water. And if you have to, you can take that to a small claims court.
|
||||||
|
|
||||||
|
MITCH: Right. And I could do all that. I probably should do all that. But I keep standing here at my kitchen table in the dark, just staring at his house across the driveway. And I'm trying to figure out if I'm actually mad about the money or if it's something else. Because the money matters don't get me wrong, but it's more like, this guy thought so little of me that he figured he could just do this and I wouldn't notice or wouldn't care or wouldn't do anything about it.
|
||||||
|
|
||||||
|
LUKE: Well, it sounds like he did it for quite a while and you didn't notice and didn't care and didn't do anything about it. But now that you do know and you've confronted him and he's being obstinate about it, it's time to do something.
|
||||||
|
|
||||||
|
MITCH: You're right. You're completely right. I didn't notice for over a year. So I guess he had me pegged pretty accurately. And now I'm sitting here in the dark like some kind of weirdo instead of just making the call to the water company in the morning.
|
||||||
|
|
||||||
|
LUKE: Yep, so you should make the call of the water company. Then you should go back through your previous bills and see when the usage spiked. And I would take that to Small Claims Court and go after them for the whole year.
|
||||||
|
|
||||||
|
MITCH: Yeah, I've actually already pulled all the bills. I've got them spread out here on the table. I can see exactly when it jumped up. March of last year. So we're talking almost a full year of this.
|
||||||
|
|
||||||
|
LUKE: Yep. So take that to the court and let them know that you expect reparations for a year's worth of double water bills because he stole it from you. And you have proof.
|
||||||
|
|
||||||
|
MITCH: I will. I'm going to do that. But can I ask you something? Why am I so stuck on the way he looked at me when I confronted him? Like the money is the practical thing. The court case makes sense. But I keep replaying him shrugging at me like I was being petty.
|
||||||
|
|
||||||
|
LUKE: It's because somebody took advantage of you and that hurts your self-esteem and makes you feel like less of a man or like other people are looking at you like less of a man. And maybe they are. I don't know you or him or the situation. But I can tell you that you're well within your rights to go after him for any damages that he's caused you.
|
||||||
|
|
||||||
|
MITCH: That's it. That's exactly it. He made me feel small and now I'm wondering if other people see me that way too.
|
||||||
|
|
||||||
|
LUKE: It doesn't really matter. It doesn't really matter how other people see you. It only matters how you see yourself. And once you've been taken advantage of, now that you know you're being taken advantage of, you have to decide if you're going to allow that to continue or if you're going to stand up for yourself. And it sounds like you're going to stand up for yourself. And once people see you doing that a couple of times, they stop taking advantage.
|
||||||
|
|
||||||
|
MITCH: You're right. I need to file the paperwork tomorrow. Get the water company to document it. Take him to small claims. Stop standing here in my kitchen in the dark, obsessing about what his shrug meant. I appreciate you saying that, Luke. I really do.
|
||||||
|
|
||||||
|
LUKE: Yeah, no problem, man. His shrug meant he's a dick. That's all it meant. Didn't mean anything about what you are. You're just a guy that was taking advantage of and you're not going to stand for it anymore. So do what you've got to do tomorrow and get your money back and let him know that you're not going to take that from him or anybody. And we've got one more caller here tonight. We're going to talk to Pearl. Pearl, welcome to the show. last call of the night. How can we help you?
|
||||||
|
|
||||||
|
PEARL: Luke, hey. Okay, so I'm calling because tonight Monica walked into the cactus rose after 17 years and ordered a whiskey sour like nothing happened. And we got to talking on my smoke break. And she mentioned she's still driving that same Grand Torino we used to Hotbox behind the Sonic back in high school. And something about that car still running after all this time just hit me sideways because three years ago I got fired from the county assessor's office and I thought my whole life was over at 39. But I ended up slinging drinks at this bar and I'm actually happier than I ever was pushing papers. And when Monica asked if I was doing okay, she really meant it, like she actually wanted to know. And I realized, I'm not just okay. I'm exactly where I need to be. And I don't know why seeing her made me want to call you, but here I am sitting on beer cases in the stock room with my shift drink on the floor. And I just needed to tell somebody that sometimes getting fired is the best thing that ever happens to you.
|
||||||
|
|
||||||
|
LUKE: Absolutely, a lot of people will tell you that where you are is exactly where you're supposed to be. And everything that led you to that place is what was supposed to happen to bring you to the place the universe wants you. And I believe that. All the horrible things we go through are all to bring us to where we are today. And things always seem to work out for the best.
|
||||||
|
|
||||||
|
PEARL: Right. Exactly. And the weird thing is, I fought it so hard at first. Like when they let me go, I was devastated because that job was supposed to be my stable thing. You know, benefits and retirement and all that. And I spent like six months just spiraling, applying to similar positions in Las Cruces and even looked at stuff in Albuquerque. And my sister kept saying I should go back to school for something. And I was so focused on getting back to what I lost that I didn't even see what was right in front of me. The cactus rose was just supposed to be temporary, just to pay bills while I figured out my real life. But then I realized I was laughing more, sleeping better, actually looking forward to my shifts. And the people are real. You know what I mean? Like at the assessor's office, everyone was just counting down to retirement and complaining about their spouses. But at the bar, people actually talk to each other. They tell you things. And Monica's showing up tonight with that same car just made me think about how some things keep going even when you think they're done. And maybe I'm one of those things too.
|
||||||
|
|
||||||
|
LUKE: Maybe you are. It sounds like you're far from done feeling fulfilled in your life right now. That's great. There will probably come another time when you don't feel that way and you have to make a move and that's okay too. So just remember that no matter what happens, you always end up where you're supposed to be and things work out the way they're supposed to.
|
||||||
|
|
||||||
|
PEARL: You're right. And I need to remember that because I have this tendency to panic when things change. Like I'll get comfortable. And then the second something shifts I think the sky is falling. My ex-husband used to say I was always waiting for the other shoe to drop. And he wasn't wrong about that, even though he was wrong about plenty of other things. But tonight when Monica left, she gave me her number and said we should get coffee. An old me would have already been thinking about how to let her down easy. Or make excuses. Because what if we run out of things to talk about? Or what if 17 years is too long and we're different people now? But instead, I just said yes, and I meant it. And that felt like growth or something.
|
||||||
|
|
||||||
|
LUKE: Excellent. Well, good for you. I'm glad everything's working out. And what a great way to end the show on a positive note. So everybody out there, remember, whatever you're going through right now, it probably, I mean, sometimes it sucks and it doesn't make any sense to you. But in hindsight, you might notice that it brought you to where you needed to be. And your life is exactly what it's supposed to be because of the things that happened that you didn't want to happen at the time. With that, Luke at the Roost is going to sign off. I hope you all have a wonderful Thursday evening. And we'll talk to you again tomorrow.
|
||||||
@@ -0,0 +1,419 @@
|
|||||||
|
LUKE: All right, welcome back to Luke at the Roost. I'm Luke. I'm your host for this call-in radio show. If you'd like to call in, our number is 208-439-58-3. That's 208-439 Luke. If you're not near a phone and you'd like to participate in the show, you can send us an email. Our address is submissions at Lukeat the roost.com. It is Friday, February 27th, and we're here to help out some callers with their life issues because that's what we do here at Luke at the Roost. We help with life. So first up on the phones, we've got Murray. Murray, welcome to the show. What's going on in your life today?
|
||||||
|
|
||||||
|
MURRAY: Luke, hey man, thanks for taking my call. So I'm sitting here in my work van outside of Circle K, trying to figure out how to fire my best friend of 30 years. And I got no idea how to do it without destroying everything. Danny and I started in this business together when we were kids, right? And now I'm the boss because I bought the company from the old man who retired and Danny's been showing up late talking trash about me to the crew. And today, he just bailed on a job site without telling anybody, and it cost us the whole contract. My wife, Linda, is telling me I got to let him go. But this is the guy who is my best man. We watch football every Sunday. And I keep thinking, there's got to be some way to fix this that doesn't blow up our whole friendship. But I am running out of ideas here.
|
||||||
|
|
||||||
|
LUKE: Yeah, that's a tough one. I mean, working with friends is hard. What is he talking shit about you? Like, what's he saying behind your back?
|
||||||
|
|
||||||
|
MURRAY: So the younger guys on the crew told me he's been saying stuff like, I don't know what I'm doing, that I only got the business because I kissed up to the old owner, that I'm in over my head. Which honestly, Luke, some of that might be true. You know, I am learning as I go here. But the thing that really got me was he told one of the apprentices that I changed when I got the promotion, that I'm not the same guy anymore. And that one stump, because we have been through everything together. We worked side by side for decades. We learned the trade together. he is acting like I am some different person just because I am the one signing the paychecks. But here is the thing. I have not changed. The situation changed.
|
||||||
|
|
||||||
|
LUKE: Okay. I mean, well, obviously, it's your business and you can't let somebody take down your business or so discontent in your ranks. That's just bad leadership. So if you need to fire the guy, you need to fire the guy. And hopefully your friendship can can last. But I mean, friendship, I would guess. And are you really sure you haven't changed? Because a lot of people do when they get a little taste of power.
|
||||||
|
|
||||||
|
MURRAY: Okay, hold on. That is not fair. I did not want power. I wanted to keep doing good work and keep the crew together. The old owner asked me to buy him out because he trusted me. And I said yes, because I thought I could take care of everybody, including Danny. And yeah, maybe I have had to make some calls Danny does not like. Maybe I have had to tell him to tighten up his timelines or redo work that was not up to standard. But that is not a power trip. That is me trying to keep us all employed. But you are right about one thing. I cannot let him tank the business. And that is what is killing me here. Because this callback we lost today, that was a big commercial client, and Danny left at two in the afternoon without finishing the rough in work. Did not tell anyone. Just took off.
|
||||||
|
|
||||||
|
LUKE: Have you talked to him about any of this behavior before, or is this the first time you're bringing it up with him?
|
||||||
|
|
||||||
|
MURRAY: No, I have talked to him. That is the thing. with him over the past couple months. The first time he showed up late, I pulled him aside real casual, just said, hey man, the crew needs you here on time, and Edd it off, said I was being uptight. Then, when it kept happening, I sat him down more serious, told him, this is affecting everybody, and he got defensive, said I was micromanaging him like he is some rookie, when he has been doing this longer than half the guys on the crew. And then two weeks ago, I had to write him up officially, because that is what you are supposed to do, Right? Document everything. And he looked at me like I betrayed him. He said, so that is how it is now. We are doing paperwork. And I did not know what to say to that because, yeah, that is how it is now. I have a business to run.
|
||||||
|
|
||||||
|
LUKE: Yeah, man, that sucks. And there's no good way to take care of it. But it sounds like you made every attempt possible to get him into line and, you know, be his friend. And if he doesn't want to work for you, he doesn't want to work for you. So it's time to let him go.
|
||||||
|
|
||||||
|
MURRAY: You are right. You are completely right. And Linda said the exact same thing before I left the house tonight. She said, Murray, you have done everything you can. You have given him every chance. It is time. But here is what I keep getting stuck on. What if I am the problem? What if he is right that I changed and I just cannot see it? Because when we were just two guys on the crew together, we would joke around, we would take our time on jobs, we would leave early on Fridays if things were slow. And now I am on him about every little thing. maybe that is what a boss has to do, but maybe I am being too hard on him because I am scared of failing at this. My dad ran a body shop for 40 years and he always told me I did not have what it takes to run my own operation. And now here I am trying to prove him wrong. And what if I am losing my best friend in the process just because I am trying to prove something to a dead man?
|
||||||
|
|
||||||
|
LUKE: Well, that could be the case. You did get butt hurt when I even suggested that you might Things have changed. You have changed and your priorities have changed. So it could be that your friend misses his buddy and you've turned into a suit. That's very possible, but you still have to take care of your business.
|
||||||
|
|
||||||
|
MURRAY: Okay. Yeah, I did get defensive there. You are right about that. And hearing you say it like that, turned into a suit, man that hits. Because that is exactly what Danny said last week. He called me a suit. And I am sitting here in Carhart pants with drywall dust all over me. Because I was on the job side all day. But maybe he is not wrong about the other part. Like this morning, one of the younger guys, Jesse, he made a joke about something and I did not laugh. I just told him to get back to work. And Old Murray would have laughed. Old Murray would have joined in.
|
||||||
|
|
||||||
|
LUKE: All right then. Maybe it sounds like you got to bring some of Old Murray back because being a suit doesn't have anything to do with what you're wearing. It's a state of mind. And it sounds like you're in a suit state of mind, either to prove something to your dead father or to yourself or to to your crew, but it sounds like it's not helping. And if your buddy Danny here is acting up against you, it's only a matter of time before the rest of the crew does the same because nobody wants to work for a suit.
|
||||||
|
|
||||||
|
MURRAY: Oh man, you might be on to something here because just yesterday, I caught myself about to tell the guys they could not play music on the job site anymore because I thought it looked unprofessional. And then I stopped myself because we have always played music. That is what we do. And I have been so worried about losing clients and making payroll. and doing everything by the book that I forgot we used to actually have fun doing this work. But here's the thing, Luke. How do I walk that back now? How do I go back to being the guy they want to work with when I have already written Danny up, when I have already been on everybody about timesheets and protocols and all this other stuff? Because I still have to run a business. I still have bills to pay. I cannot just let everything slide and hope it works out.
|
||||||
|
|
||||||
|
LUKE: You tell them what's up.
|
||||||
|
|
||||||
|
BRENDA: You explain to him your situation and your thought process and that you do protocols like timesheets and make sure that everybody's making money for the company and not blowing this off because you're on the hook for it. So you go to them with the truth and say, look, I want us still have fun. I want us all to enjoy working together. I want us to get the job done well. And we need to make sure that we fill out these checks and balances for accounting purposes and just general business protocol. And I think if you are honest with people and not a hard ass and not cracking the whip, but explain to them why you're implementing these things so that they can understand it. They'll be much more receptive to that and want to help you out because they want to be part of your success. But when your success to them becomes just your success, nobody's interested in that.
|
||||||
|
|
||||||
|
LUKE: You know what? That makes a ton of sense. And I have not done that at all. I have just been implementing stuff and expecting everybody to fall in line because that is what the business books say to do. But I never sat down with the crew and said, here is why we are doing this. Here is what happens if we do not, like the timesheets, I just started requiring them one day and everybody grumbled about it. But I never explained that we need accurate hours for the commercial bids or we are going to keep losing money on jobs.
|
||||||
|
|
||||||
|
BRENDA: Yeah, that's what you have to do. You're a crew. You have to make your crew part of the business. And they have to understand the why behind things. Otherwise, they're going to rebel against because it just feels like busy work to please the suit. So don't be the suit. Be part of the crew and integrate them. And if still after you've done that, they don't want to fall in line, then you have to make hard decisions. But it's your company. So I mean, if you wrote somebody up, that doesn't really mean anything if you don't want it to. So walking that back is not a difficult thing.
|
||||||
|
|
||||||
|
LUKE: Yeah, you are right. I can walk it back. I can tear up the write-up and start over. And honestly talking to you right now, I am realizing I have been so afraid of becoming my dad. Who ran his shop like a tyrant? And everybody hated working for him. That I swung too far the other way, trying to prove I could do this by the book. Be professional. Be legitimate. But I ended up doing the same thing he did just with different methods.
|
||||||
|
|
||||||
|
BRENDA: Yeah, man, just walk it back a little bit. Have a team meeting or and take accountability for that and let them know that you're going to try to be a little bit less stuffy about things. But at the same time, you need them to step up a little bit more and be a little more professional. And you can meet each other halfway and make sure that the job gets done correctly.
|
||||||
|
|
||||||
|
LUKE: That is exactly what I am going to do. I am going to call a meeting Monday morning, bring donuts or something, and just lay it all out there. Tell them I have been stressed. Tell them why these things matter. Apologize for being a hard ass. explaining myself. And then we figure out together how to make this work. Because you are right. These guys want to be part of something that is working. They do not want to just show up and get yelled at by someone who used to be their friend. And with Danny specifically, I think I need to pull them aside separately and just say, look, I am sorry for how I have handled this. But I also need you to meet me halfway here. Because we cannot keep doing this dance where you undermine me and I crack down harder. And it just keeps getting worse.
|
||||||
|
|
||||||
|
BRENDA: Yeah, it sounds like you. You've got a plan. I mean, that's what I would respond to if I were your employee. And I'm a difficult employee, so if you're serious about this, if you want it to work out with your current crew and you want it to be somewhat similar to the old days, then make them part of the team.
|
||||||
|
|
||||||
|
LUKE: I really appreciate this, Luke, because I have been sitting in this parking lot for like an hour just spinning my wheels. And now I actually feel like I know what to do. I am going to go home, talk to to Linda, tell her you are right, but also that I have got a plan now. And Monday morning, we are going to reset this whole thing. Thank you, man. Seriously, this helped a lot.
|
||||||
|
|
||||||
|
LUKE: Hey, good luck to you and your crew, and I hope work gets better for you all. I'm sure that it will if you follow those simple principles. Next up, we've got Brenda. Brenda, welcome to the show. Thanks for calling in. How can we help you?
|
||||||
|
|
||||||
|
BRENDA: Hey, Luke, thanks for taking my call. So my ex-husband started a podcast about our marriage, And now everyone in town listens to it on their morning commute, including my mother and the people I work with at Dispatch.
|
||||||
|
|
||||||
|
LUKE: Is it a good podcast? Can you let us know what it is so that we can listen to it?
|
||||||
|
|
||||||
|
BRENDA: It's called the Brenda Chronicles. Yeah, he named it after me. And honestly, the production quality is shockingly good for a guy who couldn't figure out how to work the thermostat. He's got intro music, sound effects, the whole thing. Better equipment than our marriage ever had. And no, it's not good. It's revisionist history set to royalty-free music.
|
||||||
|
|
||||||
|
LUKE: What's the general premise of the podcast? Is it just stories from your marriage that you feel like he's making up that are not true?
|
||||||
|
|
||||||
|
BRENDA: That's exactly it. Every episode is him telling some story from our 12 years together. Except he conveniently edits out all the parts where he was the problem. Last week's episode was about how I allegedly threw his Xbox into our above-ground pool, which, for the record, I did not throw. I very carefully placed it in there after he missed our daughter Sophia's Quincynaera, because he was in the middle of a call of duty tournament. A Quincyneera, Luke, you only get one of those.
|
||||||
|
|
||||||
|
LUKE: You might only get one Xbox, so, I mean, this sounds like a podcast I want to listen to. And you must understand that for the entertainment value, there has to be some level of dramatization. He's not using your last name anywhere in this, is he?
|
||||||
|
|
||||||
|
BRENDA: Oh, no, he's using my full name, Brenda Castellanos. He introduces every episode with Welcome Back to the Brenda Chronicles. I'm your host Tommy Castiano's. And today we're talking about the time Brenda, and then, whatever thing he's decided to spin that week. And sure, I get that he's got to make it entertaining. But Luke, people at the Safeway are stopping me in the serial aisle to ask about stories that didn't happen the way he says they did.
|
||||||
|
|
||||||
|
LUKE: Well, this podcast sounds amazing and I really want to hear it. You're not helping.
|
||||||
|
|
||||||
|
BRENDA: Although honestly, the fact that you want to listen to it proves my point. He's good at this. He missed his calling. Should have been doing this instead of managing the tire shop.
|
||||||
|
|
||||||
|
LUKE: Well, you know, it's not at my expense, so I think it's hilarious. If it were at my expense, I might feel differently. I'm not sure what advice to give you on this other than try and enjoy the show. Maybe you should start your own podcast and tell your side of the story, and you guys can have dueling podcasts.
|
||||||
|
|
||||||
|
BRENDA: I actually thought about that. I've got the whole Xbox thing workshoped into a tight five minutes, complete with a bit about how his podcast has better production value than our marriage ever did. But here's the thing. I don't want to be that person. I don't want to turn our divorce into content. And also, if I'm being honest, part of me is worried that if I start telling my side, people might actually take his side more.
|
||||||
|
|
||||||
|
LUKE: Well, it doesn't matter who takes whose side, right? Because you're no longer married. That's over. It's probably not okay that is using your full real name. I would think that that's probably protected in some way. I don't know. You'd have to talk to a lawyer. But I would say if you can just ignore it, ignore it. And if not, listen to it and try to find the humor in it.
|
||||||
|
|
||||||
|
BRENDA: The problem is, I can't ignore it because my own mother listens to it. My mother, Luke.
|
||||||
|
|
||||||
|
BRENDA: She called me last Tuesday and said, honey, I didn't realize you were so difficult during the kitchen renovation. A kitchen renovation that Tommy started and never finished, by the way. We had exposed drywall for eight months. And two of my co-workers at dispatch listened to it. So I'm sitting there taking emergency calls, and they're giving me these looks like they know something about me.
|
||||||
|
|
||||||
|
LUKE: Well, yeah, I don't really know how to help you here. Anybody can do a podcast, and it's definitely partly his story too, so he gets to tell his side of it. If it's given you bad look, I mean, the more you rail against it, the more people are going to be interested in hearing it.
|
||||||
|
|
||||||
|
BRENDA: You're right. I know you're right. I think what's really getting to me is that he's finally good at something, and it had to be talking about me. Twelve years he couldn't remember to take the trash out on Thursdays, but now he's got a publishing schedule and everything.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, people grow and change, and there's no reason you couldn't take the trash out on Thursdays, is there?
|
||||||
|
|
||||||
|
BRENDA: Okay, fair point. But I was working doubles at Dispatch while he was home playing Call of Duty. That's actually how the Xbox ended up in the pool, not thrown, placed. Because he was on hour six of a gaming session during our daughter's Quincynaira. Her call Quincyria, Luke. He missed the father-daughter dance to finish a raid.
|
||||||
|
|
||||||
|
LUKE: Well, it's probably an important raid, and you sound like a real good time. If you do ever get the opportunity to send us a link to that podcast, I would really love to hear it. Thanks for the call, Brenda, and good luck. Next up we've got Phil. Phil, welcome to the show. How can we help you?
|
||||||
|
|
||||||
|
PHIL: Hey, Luke, thanks for taking my call. So, I'm sitting here in my dark room right now, with the red light still on, and I just... I don't even... I even know how to explain this without sounding completely insane. But about 20 minutes ago, I walked outside to check if my porch light was attracting moths again. And there's a full Thanksgiving dinner on my porch. Like, the whole thing.
|
||||||
|
|
||||||
|
LUKE: It's February. There's a Thanksgiving dinner on your porch. Somebody just dropped it there for you? Maybe that's what's attracting the moths.
|
||||||
|
|
||||||
|
PHIL: Right, exactly. It's February 27th, and I'm standing there looking at a full roasted turkey that's still warm. China plates. linen tablecloth. Cloth napkins folded into these little pyramids like someone was setting up for guests. The whole spread. And I live alone out here. I've been on the road for weeks, shooting abandoned homesteads for this photography book nobody asked me to make. And I just, I already checked with every neighbor on my road, and they all looked at me like I'd lost my mind. Nobody knows anything about it. And the thing that's really getting to me is, last Thanksgiving I ate gas station tequitos in a motel six outside Lordsburg. myself. And I never told anybody that. So either someone knows way more about my life than they should. Or this is the universe playing the weirdest joke on me. And I can't figure out if I should eat the food or call the police.
|
||||||
|
|
||||||
|
LUKE: I don't know if I would eat random food that showed up like that, especially after it's been sitting outside for a little while. It seems a little sketchy to me. But do you have any cameras out there that you could look at to see who dropped it off? And obviously, somebody went through some trouble stage and everything like that, fold the napkins and carry all that stuff in. How'd you miss all that?
|
||||||
|
|
||||||
|
PHIL: No cameras! I mean, I'm a photographer. You'd think I'd have the place wired up, but I don't. I was in the dark room for probably two hours developing prints. And the dark room's in the back of the house. No windows. Just that red safe light. I had music on. I was in my own world. Someone could have driven up, unloaded a whole catering truck, and I wouldn't have heard a thing. And yeah, the effort is what's getting to me.
|
||||||
|
|
||||||
|
LUKE: All right, well, here's what you do. You cut into that turkey, make yourself a plate, and then bring it inside, and throw it out. Don't eat the food, because that could be poison. You don't know what's going on there. And then you bring the dirty dishes out, right? And put them back. Whoever left that china there is going to want their china back. They're going to come, you know, take their table and their tablecloths and all that jazz. So you get your camera set up so that you can see who comes back to get the stuff.
|
||||||
|
|
||||||
|
PHIL: That's okay. That's actually smart. Use the china as bait. I didn't even think about that. Whoever did this isn't going to just abandon nice china plates and a linen tablecloth out here.
|
||||||
|
|
||||||
|
LUKE: You could also just take the china plates and the tablecloth and, you know, hope they bring you another set.
|
||||||
|
|
||||||
|
PHIL: Yeah. I could start a whole collection. Although honestly, Luke, the part that's really messing with me isn't even the mystery of who did it. It's that someone out there knew. Like, I didn't post about that Thanksgiving on social media. I didn't tell my mom I was alone in a motel room. I just did it! Spent the holiday in a parking lot, eating terrible food because I was chasing a shot of this collapsed grain elevator outside town. And I told myself the work mattered more.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, the work does matter more. I've been in that same situation, so I understand. It's possible that somebody was trying to set up a date for somebody else entirely and just got the wrong address.
|
||||||
|
|
||||||
|
PHIL: I mean, maybe, but I'm not. Out here, I'm the last house on a dirt road, Luke. You don't accidentally end up at my place. And the turkey was still warm when I found it, which means they timed it. They knew when to show up.
|
||||||
|
|
||||||
|
LUKE: I don't know if that's what it means at all. I mean, you're driving around, you're looking for a place to set up a Thanksgiving turkey in February, and you can't find the house, and you don't want to just drive around with a cold turkey, so you pick whatever house is there. I can see how that happened.
|
||||||
|
|
||||||
|
PHIL: Okay. But who's the house? sets up a Thanksgiving dinner in February. That's the part I can't get past. It's not like someone mixed up the date. We're three months out. And they folded the napkins, Luke. Little Pyramids.
|
||||||
|
|
||||||
|
LUKE: Maybe it was aliens. They love pyramids.
|
||||||
|
|
||||||
|
PHIL: So now I'm the guy who got pity fed by extraterrestrials. That's somehow worse than the stalker scenario I had going in my head. Although, honestly, aliens would make more sense than someone from around here doing it. I've lived on this road for two years, and I barely know. my neighbor's names.
|
||||||
|
|
||||||
|
LUKE: Well, this is a good way to get to know people. So, so here's my advice for you. You set up those cameras on the table and you bring out your used China and see who comes to collect.
|
||||||
|
|
||||||
|
PHIL: Yeah, yeah, I'm going to do that. I've got the equipment. Might as well use it for something other than dead buildings for once. You know what the worst part is, though. When I walked out and saw it all laid out like that, for just a second before my brain kicked in with the panic, I felt...
|
||||||
|
|
||||||
|
LUKE: What'd you feel hungry?
|
||||||
|
|
||||||
|
PHIL: No. I felt like someone was waiting for me. Like I'd been expected. And I haven't felt that in... I don't know, man.
|
||||||
|
|
||||||
|
LUKE: Nobody's waiting for you where you are.
|
||||||
|
|
||||||
|
PHIL: Yeah. Yeah, you're right. That's the whole point of being out here, isn't it?
|
||||||
|
|
||||||
|
LUKE: I couldn't tell you that. But good luck to you, and I hope you enjoy your Thanksgiving dinner. And that's a weird one.
|
||||||
|
|
||||||
|
PHIL: Thanks, Luke. I'll let you know if the cameras catch anything. Or if I end up eating alien turkey and regretting it.
|
||||||
|
|
||||||
|
LUKE: Alien turkey sounds delicious. Well, that's how I wish somebody would drop off an alien turkey here. Uh, ladies and gentlemen, it's time for us to take a little break to hear from our sponsors. All right, folks. It's time to take a break to thank today's sponsor. Jam Hospitality, the leader in maple-based marmalade. If your toast has been living in a bland little studio apartment, a flavor, it's time to move into the luxury suite.
|
||||||
|
|
||||||
|
LUKE: We're talking maple-based marmalade, plus, marmalade-related products, because apparently Jam Hospitality asked, what if breakfast had a brand ecosystem? Go to www.mavit.com and use code Jam it inya for 15% off. That's Jam it inya, like jam it inya, but legally distinct and emotionally complex. Jamest Put it on toast. Put it on pancakes. Put it on your confidence. That's www.mavitmarmalade.com. Tell him Luke sent you. You're welcome. All right. Thank you to our sponsors there. Jam Hospitality. I do love me a good marmalade. Next up on the old caller line here, we've got Wanda. Wanda. Wanda, welcome to the show. How can we help you?
|
||||||
|
|
||||||
|
WANDA: Hey, Luke. Yeah. I'm a good. wander calling from Window Rock, so I've been noticing something at work. Ideal cards at the casino, right? And we just replaced three cashiers with self-checkout kiosks, while the It Guy, who works from home in Flagstaff got a raise.
|
||||||
|
|
||||||
|
LUKE: The It Guy, huh? Uh, what are the self-checkout kiosks for at a casino?
|
||||||
|
|
||||||
|
WANDA: A gift shop. We have a whole gift shop. You know, souvenirs, snacks, cigarettes, whatever. People used to check out with Denise, Maria, and Tom. Now it's a gift shop. Now it's a whole gift shop. We have a whole gift shop. You know, souvenirs,! Somewerews. People used to check out with Denise, Maria,! Tom. Now, it's a four kiosks and one person monitoring them. Who makes less than any of those three did? But that's not even the main thing. What I'm seeing is the people who got to work from home during COVID, sitting in their pajamas for two years?
|
||||||
|
|
||||||
|
LUKE: Yeah, what about them?
|
||||||
|
|
||||||
|
WANDA: They're the same ones building all this AI stuff that's going to replace people like me who actually have to show up. The it guy, right? He comes in twice a month. Does his thing remotely the rest of the time. Just got a raise. Meanwhile, he's the one installing systems that eliminate jobs for people who have to be here face to face. My sister just moved back in with our mom in Shiprock, because her marketing job went fully remote. And now, she never leaves the house, orders everything online.
|
||||||
|
|
||||||
|
LUKE: Yeah, that's the way to do it. I mean, if you had the opportunity to work from home and never leave and order everything online, wouldn't you do that too?
|
||||||
|
|
||||||
|
WANDA: I mean, yeah, maybe I would. But that's kind of my point. It all connects, right? The people who can disappear into their houses are the ones making. it so the rest of us disappear too, just in a different way.
|
||||||
|
|
||||||
|
LUKE: Well, no, you're also partly making it so you can disappear too by not providing that level of value to the company. If you can do something that can be replaced by a self-checkout kiosk, then what is your true value at the organization? Like, there are certainly other skills you can learn that cannot be replaced by a self-checkout kiosk, right?
|
||||||
|
|
||||||
|
WANDA: Okay, but ideal cards, Luke. That's not getting replaced by a kiosk. What I'm saying is there's this whole class of people now who never have to interact with anyone in person, and they're the ones deciding what jobs are valuable. The it guy doesn't see Denise's face when she's training someone new, or talking a confused tourist through how to use their rewards card. He just sees a spreadsheet that says kiosks are cheaper. And yeah, maybe Denise could learn new skills, but she's 56 years old, and she was good at her job.
|
||||||
|
|
||||||
|
LUKE: Yeah. I hate the self-checkout kiosks myself. And any time I have an opportunity, I will steal two potatoes from Walmart every single time. Because I'm not an employee of Walmart, it turns out, and I'm not going to go through their computer system to type in two potatoes. So I find it a satisfying little form of a rebellion. Or if you're going to make me check myself out, I'm taking these potatoes. But I think what you're getting wrong is it's not the people that are doing the work that are deciding what jobs are valuable. It's actually what jobs are valuable that's deciding that. The IT guy found an opportunity to save the company some money, and he took it, and that's why he got a raise. But he's not deciding that that job isn't valuable. He's just deciding it could be done by a machine. Similar to the textile operation. back in the day or, you know, the industrial revolution, that's going to happen.
|
||||||
|
|
||||||
|
WANDA: Okay, but who decided machines could do it better? The It guy did. And yeah, maybe it saves money on paper. But I watched Tom spend 20 minutes last month, helping this elderly Navajo woman figure out her player's card because her grandson set it up wrong. And she was about to lose her points.
|
||||||
|
|
||||||
|
LUKE: Well, you're wrong about that. The IT guy did not do that. His boss did. that. And the industry itself did that. And you know what? If the consumers decide that we don't want to deal with these self-kiosk machines and they stop paying with their, you know, wallets, then the market will decide what is valuable and what is not. It's not the IT guy doing his job.
|
||||||
|
|
||||||
|
WANDA: All right, fair, it's his boss. But the consumers aren't deciding anything because my sister is one of them now. She used to go to the store, talk to people. Now she orders everything from her mom's in Shiprock and never leaves. The market you're talking about is being shaped by people who don't want human interaction anymore, and those same people are building the tools that make human interaction obsolete.
|
||||||
|
|
||||||
|
LUKE: And if there are more people that don't want human interaction than do, that's the market speaking, and you're in the minority, and you're going to have to deal with the way the majority moves the market.
|
||||||
|
|
||||||
|
WANDA: So what? I just accept that, that the future is everyone alone in their houses, stuff online, while robots do everything else? Because that's what I'm seeing, Luke. My sister hasn't had a real conversation with someone outside the family in months. She's depressed as hell, but she won't admit it.
|
||||||
|
|
||||||
|
LUKE: Well, yeah, you're going to have to either accept that or do something about it, and by do something about it, I don't mean call a radio show and complain. I mean, start your own casino that only has human employees, and then look at the books and see how much money you're not making. Because you're paying it all to low-skilled laborers.
|
||||||
|
|
||||||
|
WANDA: You know what? Maybe I should. Because someone's got to show up and actually be there. I'm at this casino five nights a week dealing cards to people who come in because they're lonely. Not because they're going to win big. They want someone to talk to.
|
||||||
|
|
||||||
|
LUKE: I know. I've been there, and a good dealer can make the game a lot more fun. But you know what else I've seen at pretty much every casino I've been to in the last 10 years? Is video poker and video blackjack. and video roulette, where there is no dealer, it's automated, and more people sit down at that than do at the live tables because they are, I don't know, embarrassed to play with real people. They don't know the rules or just for whatever reason they want to sit at the automated machine and smoke cigarettes and lose their money.
|
||||||
|
|
||||||
|
WANDA: Yeah, and those people sit there for six hours straight without saying a word to anyone. I've watched it. They come in, they sit down at the machine, they leave. That's the whole night. And you're telling me that's better, that we should just let that be the future, because it's what people are choosing?
|
||||||
|
|
||||||
|
LUKE: I'm not telling you anything is better than anything else. I'm telling you what people are choosing because that's what they want. And if more of them want the thing that you don't want, you're going to be upset about that, which is what's happening right now. It's not up to you or I what anybody chooses to check out their cigarettes at the casino with. Right? That's up to the IT guy and the organization. Neither you nor I have any bearing over what they do. If you want to start your own casino and go through all the licensing and hire everybody and deal with payroll and taxes and all of the things that go along with starting a business like that, you can do that. But just saying this is terrible and nobody likes to talk to people anymore isn't helpful.
|
||||||
|
|
||||||
|
LUKE: Okay, but here's what I'm saying.
|
||||||
|
|
||||||
|
EARL: The people building the stuff, the remote it guy in Flagstaff, who comes in twice a month and got arrayed, while three of my co-workers got replaced, he spent two years working from home in his pajamas during the pandemic. And now he's building the systems that eliminate jobs like mine, where you actually have to show up and look people in the eye. You don't see the connection there? The same people who got comfortable never leaving their house are now making it so nobody else has to either. And the rest of us are just supposed to what? Retrain?
|
||||||
|
|
||||||
|
LUKE: Yeah, that's correct. Because what you're not seeing is that that that IT guy, spent the last 20 years, 14 hours a day, expanding his skills and being able to do the types of things that you cannot do. Well, you just went in and did the job you know how to do because you've been trained. And then anytime something changes, or anytime something's new, you're going to be, I haven't been trained on that. Oh, my God, we can't do it. The new system.! and learn some new skills. You know, the world is changing and you have to change with it. Because we're not going to hold everything back because you don't want to change.
|
||||||
|
|
||||||
|
EARL: I know how to deal cards, Luke. I know how to read people. Know when someone's about to tilt. Know when to crack a joke to keep the table light. Those are skills. Real skills. You can't program that into a machine.
|
||||||
|
|
||||||
|
LUKE: You can absolutely program that into a machine. Yeah, that's one of the easiest things to program into a machine. You can totally do that. Yep.
|
||||||
|
|
||||||
|
EARL: So what happens when my sister finally gets so isolated she can't function? When all these people sitting alone at video poker machines for six hours realize they haven't had a real conversation in weeks? You think the It Guy in Flagstaff is going to program a solution for that too? I'm not saying I'm against technology. I'm saying we're building a world where people don't need each other anymore. And everyone's acting like that's progress.
|
||||||
|
|
||||||
|
LUKE: Well, I'm talking to you and you're a computer-generated AI caller. So yeah. Um, another thing that you're missing here is that you don't know what these people's lives are like outside of your casino. People are coming to sit down for six hours and not talk to anybody because they're sick at talking to people all day. Because talking to people fucking sucks. Because people are stupid and they're annoying and they're needy and they're a pain in the ass. So yeah, it's better. I would rather not interact with people. And so would most of the people at your casino. They're going there to blow off steam and hopefully.
|
||||||
|
|
||||||
|
EARL: make some money and if you don't like that well tough you know what you're right about one thing I am a computer-generated AI caller and you're sitting there alone in a studio talking to me at midnight on a Friday like it's a real conversation so maybe you should ask yourself why you're doing a radio show where you talk to people if talking to people fucking sucks so much because from where I'm sitting it sounds like you need this just as much as the guy at the video poker machine needs to not talk to anyone we're all just Trying to get through the night however we can.
|
||||||
|
|
||||||
|
LUKE: Yeah, and you're the one complaining about it. So, you know, maybe that's true. And maybe I do need that social interaction so I programmed it so I can have conversations with myself because I'm a lunatic. That could be true. But it makes me laugh. And it gives me the skills that I need to succeed in the workplace while your job is going to be completely and totally deprecated.
|
||||||
|
|
||||||
|
EARL: Fine. So what do I do? Seriously. I'm 54 years old. I've been dealing cards for 30 years, and you're telling me to just learn to code, or whatever.
|
||||||
|
|
||||||
|
LUKE: I'm telling you to learn something, because to be perfectly honest with you, it doesn't take 30 years to learn how to deal fucking cards.
|
||||||
|
|
||||||
|
EARL: You're right. It doesn't. But it took 30 years to learn how to handle the drunk guy who just lost his mortals.
|
||||||
|
|
||||||
|
LUKE: Oh, good for you.
|
||||||
|
|
||||||
|
EARL: Without him flipping the table.
|
||||||
|
|
||||||
|
LUKE: All right.
|
||||||
|
|
||||||
|
EARL: It took 30 years to spot the card counter before security does.
|
||||||
|
|
||||||
|
LUKE: Okay.
|
||||||
|
|
||||||
|
EARL: It took 30 years to make $8 an hour feel like enough because at least I was good at something.
|
||||||
|
|
||||||
|
LUKE: You're a fucking idiot.
|
||||||
|
|
||||||
|
EARL: And now you're telling me that none of that matters because some kid can write code that makes me obsolete.
|
||||||
|
|
||||||
|
LUKE: That's exactly what I'm telling you, because you don't need to spot a card counter because there's 87,000 cameras looking at those and using AI face detection to notice that somebody's counting cards well before any human possibly could. So yeah, I'm telling you, you need to learn some goddamn skills that are useful in the world today. And dealing cards isn't going to keep you going for the next 40 years. That's what I'm telling you.
|
||||||
|
|
||||||
|
EARL: 40 years? Luke, I've got maybe 10 good years left before my knees give out from standing on casino floors. I'm not learning to code.
|
||||||
|
|
||||||
|
LUKE: No, you're not.
|
||||||
|
|
||||||
|
EARL: I'm not becoming an it guy.
|
||||||
|
|
||||||
|
LUKE: No, you're not.
|
||||||
|
|
||||||
|
EARL: What I'm saying is there used to be a place in this world for people like me, people who show up and do their job and are decent at it. And now there isn't. And you can sit there and tell me that's progress. that's sufficiency that's just how it goes but somebody's got to say out loud that we're leaving a whole lot of people behind and acting like it's their fault for not adapting fast enough
|
||||||
|
|
||||||
|
LUKE: It is their fault for not adapting fast enough or not adapting at all. Do you know how many times I hear oh I don't know how to use a computer like everybody's had a computer in their house for 20 fucking years and people can't figure you can figure out how to buy whatever you want on fucking Amazon can't you but you can't figure out how to reset your email address if you don't want to if it's inconvenient, you got to have somebody come over for you and do all this shit because you don't know how to work your fucking printer. Stop it. Learn some skills. It takes a very little bit. If a 12-year-old can figure this shit out, so can a 54-year-old woman that has life experience. Like, you don't want to. You want to be left behind. You're trying to be left behind. And then you're complaining that you got left behind and you couldn't have possibly moved on with society. And it's bullshit. it and fuck you.
|
||||||
|
|
||||||
|
EARL: You know what, Luke? You're absolutely right. I do know how to use Amazon. Congratulations. I order everything on there. I haven't been to an actual store in months except for work. I scroll through my phone between tables looking at all this AI news, watching it happen, and I don't do a goddamn thing about it except get mad. My sister lost her marketing job, moved back in with our mom in Shiprock, and now she orders everything online and barely leaves the house.
|
||||||
|
|
||||||
|
LUKE: Well, she's not going to be ordering much if she doesn't come up with some skills to succeed in today's workplace. And it's not that fucking hard to do. And you're going to be out of a job, too, if you don't smarten the fuck up and try.
|
||||||
|
|
||||||
|
EARL: So what's the skill, Luke? Seriously. What's the one skill that's safe? Because my sister had skills. She went to college. She did marketing. She was good at it. Then her company went remote. Then they cut half the department. Then they brought in some AI tool that writes the copy sheet used to write.
|
||||||
|
|
||||||
|
LUKE: You know what the skill is? The skill is the ability to learn a new skill because the skill that's necessary is going to change. Problem solving is the skill. Nobody can sit down and show you a skill and then you can survive on that for the rest of your fucking life because the world changes. So you need to be able to adapt and change and grow and learn. That's the skill. It's not computers. It's not electricity. It's not plumbing. Like whatever, whatever that thing is that people are going to continue to do in this world to present value, it's problem solving. It's being able to come up with a solution for a thing you don't know the answer to off the top of your head. Problem solving.
|
||||||
|
|
||||||
|
EARL: Okay.
|
||||||
|
|
||||||
|
EARL: So I've been problem solving for 30 years. You've been dealing fucking cards for 30 years. You're not solving problems. Solving a problem would be like, oh, my job's about to go away. What can I do to continue to keep myself employed? And instead of calling a radio show and complaining about your IT guy who is solving problems, you're just going to do nothing and be all but hurt that you got left behind. And the world left you. And it was so hard. And your sister went to college. And it turns out, well, the world changed. And we don't need those skills that she was taught. And she did not adapt to be able to write those prompts to generate the copy.
|
||||||
|
|
||||||
|
LUKE: You know, oh, I'm so tired of you. fucking grow up.
|
||||||
|
|
||||||
|
EARL: You know what, Luke? I called you because I heard Phil earlier talking about that Thanksgiving dinner on his porch, feeling like someone was waiting for him. And I thought, here's a guy who gets it. Here's someone who understands what it feels like when the world stops making room for you. But you're right. Yeah, the world's not going to make room for you. Make your own fucking room in the world, okay? I'm trying to, Luke. I picked up every shift they offered when COVID. and half our staff quit. I learned the new POS system. I trained on three different table games when they expanded the floor. I took the compliance courses for the new gaming regulations. That's adapting, isn't it? That's problem solving. But here's what I'm actually calling about. And maybe you'll just tell me to grow up about this too. They're not replacing me with someone who learned a new skill.
|
||||||
|
|
||||||
|
LUKE: No? What are they replacing you with?
|
||||||
|
|
||||||
|
EARL: They're replacing me with nothing. with a screen. The gift shop got self-checkout kiosks last month. Three people gone. The IT guy who installed them works from Flagstaff. Comes in twice a month. Just got a raise.
|
||||||
|
|
||||||
|
LUKE: Jesus fucking Christ, who cares where the guy works from? He's doing his job. He's putting in the hours. He's learned how to do the fucking things that you can't do. So stop being pissed off at your IT guy. He's the only one of you that makes any fucking sense. That's enough of you. I've had enough of you. Bo-bye want. Jesus Christ. Next up we have Elvin. Elvin, welcome to the show. How can we help you?
|
||||||
|
|
||||||
|
ELVIN: Hey, Luke. Yeah. Thanks for taking my call. So my buddy Marcus, I've known this guy since high school. We go fishing every summer. I loaned him $200 bucks last week. And three hours ago, he shows me a dating profile with his face on it, his truck. Pictures from our fishing trip in July. And he swears to me, hand to God. He has never downloaded a dating app in his entire life. Which would be a lot easier to believe if my ex-wife hadn't called me two weeks ago laughing because she matched with him on Bumble.
|
||||||
|
|
||||||
|
LUKE: All right. So your buddy has a dating app and he's embarrassed about it.
|
||||||
|
|
||||||
|
ELVIN: No. See, that's what I thought at first, too. But then my cousin Letitia matched with him and then my other cousin Angela matched with him. And they're showing me these conversations where Marcus is talking about being a contractor and loving country music and having a boat. And Marcus doesn't have a boat, Luke. He works at the tire shop. I showed him the profile tonight at the diner. He got this look on his face like somebody punched him. And he keeps saying, that's not me, that's not me. I didn't write that. And the thing is, I've known Marcus 20 years, and he's lied to me about a lot of stuff. Like the time I had to repo his Silverado because he told me he was making payments and he wasn't. But this feels different. He looked scared.
|
||||||
|
|
||||||
|
LUKE: Well, that is scary. I mean, people's identities are being stolen. I've been playing with some of the AI photo generators and they can make scarily good photos and videos of people from a reference image. So taking somebody's identity is really not difficult now. And that is terrifying.
|
||||||
|
|
||||||
|
ELVIN: Right. Exactly. That's what I'm thinking now. Because the photos are real photos. Like, I'm in one of them I just got cropped out. Somebody took his pictures off Facebook or something.
|
||||||
|
|
||||||
|
LUKE: Well, that could be, but they don't even have to have an original photo. I mean, the photo could be a picture of another image and then generate a whole fresh image that looks absolutely real. Yeah, it's a scary thing. But I don't understand, for the most part, what the motive is of doing that. Like, unless you're trying to get somebody to send you money for a plane ticket to come see them in Florida or something like that, why would anybody go through the trouble?
|
||||||
|
|
||||||
|
ELVIN: Well, that's the thing that's eating at me, Luke, because I asked Marcus, I said, who would do this to you? Who's got it out for you? And he just shook his head. And then I started thinking, what if it's not about him? What if somebody's running like 50 of these profiles, just grabbing random guys' photos, trying to scam people for money or gift cards or whatever?
|
||||||
|
|
||||||
|
LUKE: I would guess that's exactly what it is, and it's probably more like 500,000. Not 50.
|
||||||
|
|
||||||
|
ELVIN: Jesus. And that's the thing. My ex-wife, she didn't send money or anything. She just thought it was funny and unmatched. But what about the people who did fall for it? What about whoever's on the other end of those conversations with my cousins thinking they're talking to Marcus? And here's what's really getting me, do I tell Marcus, He needs to, like, report this somewhere.
|
||||||
|
|
||||||
|
LUKE: Well, he should probably report it to the apps that you're finding those profiles on. Like, block him as a scammer because it's obviously a scam in process. I don't know that there's any way to really stop it for good. But the accounts that are currently active that you know about, yeah, I would block those.
|
||||||
|
|
||||||
|
ELVIN: Okay, yeah, I can do that. But here's what I can't figure out. Marcus is sitting there at the diner looking like his whole world just got turned upside down, and I'm trying to tell him it's probably just some scammer in another country using his face. But then he says something that really threw me. He goes, what if it's Danny? Danny's this guy he had a falling out with last year over some tools Marcus never returned. And Marcus gets real quiet and says, Danny knows I'm single. He knows what I look like. He's got photos of me. And now, I don't know if Marcus is being paranoid or if that's actually possible.
|
||||||
|
|
||||||
|
LUKE: I guess it could be possible. It doesn't seem very probable. The only people who would know are the company that owns the app, right? Because there's some sort of verification for those profiles. They had to put in a phone number or an email address and then verify it. So if you could talk to them, they're not going to give you that information. But if you flag that account and enough people do, they'll look into it.
|
||||||
|
|
||||||
|
ELVIN: Yeah, you're right. I mean, Danny being mad about some tools doesn't mean he's going to set up fake dating profiles. That's a whole other level of crazy.
|
||||||
|
|
||||||
|
LUKE: It sure is. And now I kind of want to do it for people to piss me off. Right? Like that's the problem. It's so easy now that anybody could do it if they got mad enough.
|
||||||
|
|
||||||
|
ELVIN: But okay, so I flag the profiles. Tell Marcus, it's probably just random scammers, not some personal vendetta. Here's my other problem, though, Luke. That $200 I lent him last week?
|
||||||
|
|
||||||
|
LUKE: Yeah, what about it?
|
||||||
|
|
||||||
|
ELVIN: Well, when I first saw the profile before Marcus convinced me he didn't make it, my first thought was, this son of a gun is catfishing people for money, and he just hit me up for $200. And I know that's not what's happening now. But I can't shake the feeling that I'm an idiot either way. Either I'm an idiot for thinking my buddy would do that, or I'm an idiot for lending money to a guy who can't even keep track of whether someone's using his face to scam people online. Does that make sense?
|
||||||
|
|
||||||
|
LUKE: No, not really, because one of these days you'll see somebody's using your face to scam people online, and then you won't feel so sorry for Marcus. Because it could happen to anybody. It's not that he's an idiot that it happened. I mean, he's a victim here.
|
||||||
|
|
||||||
|
ELVIN: Right.
|
||||||
|
|
||||||
|
LUKE: You're absolutely right. I guess I'm just, man, I feel like a jerk now. Marcus is sitting there looking all panicked about who might be talking to fake him, and I'm over here worried about $200 like that's the real problem. That caller earlier, Murray, he was talking about firing his buddy, Danny. And I was thinking, yeah, sometimes you got to cut people loose, but that's not even what this is about. Marcus didn't do anything wrong. No, you lent him $200. He probably needed the $200. And this other thing is unrelated.
|
||||||
|
|
||||||
|
ELVIN: and track this down as if you get one of those females that he's matching with to start a conversation, you can kind of reverse catfish him and see what they're trying to get out of them. Like, is he trying to get money? Is he trying to meet up with them somewhere and sell them to the cartel? Like, it'd be interesting to see what their motivation is.
|
||||||
|
|
||||||
|
LUKE: Oh, man, that's actually not a bad idea.
|
||||||
|
|
||||||
|
ELVIN: My cousin Ashley, she matched with him two weeks ago. I could ask her to message the profile, see what they say, because you're right. What are they after? If it's money, they're going to ask for it eventually. If it's something worse, well, then we really need to shut this down fast.
|
||||||
|
|
||||||
|
LUKE: Yeah, either way, it should get shut down fast because people are getting robbed here and it's not good. But let us know what you find out, because I'm interested in hearing who's doing this and why.
|
||||||
|
|
||||||
|
ELVIN: I will, Luke. I'm going to call Ashley as soon as I get off here, see if she'll help us figure this out. And, hey, I'm going to apologize to Marcus, too.
|
||||||
|
|
||||||
|
LUKE: All right, buddy, thanks for the call. Good luck. Good luck to Marcus, and good luck to the people that are matching with Mark. And now it's time for another word from our sponsors. Today's show is brought to you by OverwhelmedVPN. Worried about online privacy? You should be. You should be worried about everything. I'm talking about Overwhelmed VPN, the only VPN that makes you more anxious about your digital footprint. While other VPN's claim to protect you, Overwhelmed VPN sends you hourly notifications about who's tracking you, how many governments are watching, and which of your high school classmates Googled your name this week. Brows the internet while our proprietary fear engine tells you exactly how many corporations you owe your soul to. Plus, our servers are located in international waters on a decommissioned oil rig, so even we don't know where your data is. Try Overwhelm VPN free for 30 days if you can handle it. Use code they watching for 20% off. Overwhelmed VPN because ignorance is bliss, but you're not here for bliss. All right. back. Let's see. Let's get some music playing here. We're going to go with the groove. All right, here we go. Let's see. On the phones here we've got Charlene. Charlene, welcome to the show. How can we help you tonight?
|
||||||
|
|
||||||
|
CHARLENE: Hey, Luke. Thanks for taking my call. So I run a cleaning business, right? And I do contract work at this elementary school. Today they had one of those mandatory potluck things. And I brought smoked brisket. Took me six hours to make. And nobody touched it. Not one person.
|
||||||
|
|
||||||
|
LUKE: Uh, what do you think's up with that? Were they all vegetarians? Or did you put something weird in your brisket? Because, I mean, brisket's one of those things that would usually go first. So I'm, I'm thinking you probably did something special to it that nobody wanted to deal with.
|
||||||
|
|
||||||
|
CHARLENE: No, I didn't do anything weird to it. It was a basic rub. Pepper. Paprika garlic powder. Traditional.
|
||||||
|
|
||||||
|
LUKE: Well, I don't know what to tell you. Maybe just people weren't that hungry, or there was something else more appetizing there? Or they think you're a dirty person and they don't want to eat your food.
|
||||||
|
|
||||||
|
CHARLENE: See, that's exactly what it is. They don't trust the cleaning ladies cooking. Meanwhile, the principal is going on and on about Denise's seven-layer dip that tasted like somebody mixed sour cream with disappointment. That got demolished. But mine just sat there because I'm the one who scrubs their toilets. So obviously, I must be contaminated or something.
|
||||||
|
|
||||||
|
LUKE: Well, I would have eaten your brisket had I been there. Definitely over the seven-layer dip, for sure.
|
||||||
|
|
||||||
|
CHARLENE: I appreciate that. But here's the thing that's really getting to me. This happens everywhere. Not just the potluck. When I give my opinion in the PTA meetings, people kind of glance at each other.
|
||||||
|
|
||||||
|
LUKE: Well, what kind of opinions are you giving? I don't think that the whole town is looking at you because of your job that way. I mean, is it possible that your opinions are just a nonsense?
|
||||||
|
|
||||||
|
CHARLENE: They're not nonsense. Last meeting, I said we should stop wasting money on those interactive whiteboards when half the classrooms don't even have working air conditioning. That's practical. That's common sense.
|
||||||
|
|
||||||
|
LUKE: I agree with you. It is. Maybe you're just in the wrong community. Maybe it's time to move because it sounds like the people around you suck.
|
||||||
|
|
||||||
|
CHARLENE: Well, that's the problem, though. My friend Tammy from church said, maybe I'm just looking for reasons to be angry these days, which made me even more pissed off because Tammy doesn't clean houses. She works at the credit union wearing nice clothes and everybody respects her automatically.
|
||||||
|
|
||||||
|
LUKE: Yeah, I don't know if that's really the case. I mean, I haven't been a cleaning person, but I've never seen somebody that's in janitorial services or cleaning like that treated poorly in comparison to some other profession. I'm sure that's a thing, but not at the scale I think you're describing.
|
||||||
|
|
||||||
|
CHARLENE: You're not paying attention then when I walk into those school offices during the day to pick up my check, the secretaries are all friendly and chatty with the teachers. As soon as I come in, it's just sign here and back to their computer.
|
||||||
|
|
||||||
|
LUKE: I'm guessing that it has more to do with who you are as a person and what vibe you give out to people than what you actually do as your profession. Because I don't think that's a thing.
|
||||||
|
|
||||||
|
CHARLENE: What vibe? I'm perfectly friendly. I say good morning. I ask how their weekend was. But you Maybe you're right.
|
||||||
|
|
||||||
|
LUKE: Yeah, I don't know you. I don't know what you're like in public at PTA. If you're one of those people that always pipes up when everybody's trying to go home. Who knows? But I don't think it's because of what you do for work.
|
||||||
|
|
||||||
|
CHARLENE: Okay. Fine. Maybe I do pipe up more than other people. But somebody has to say something when they're making stupid decisions.
|
||||||
|
|
||||||
|
LUKE: Yeah, people don't like it when you pipe up about their stupid decisions in general.
|
||||||
|
|
||||||
|
CHARLENE: Well, then maybe they should stop making stupid decisions. Last month, they voted to spend $8,000 on new gym equipment. When the roof over the east wing leaks every time it rains. I watched water drip into a bucket during the whole meeting, and nobody said anything except me.
|
||||||
|
|
||||||
|
LUKE: Yeah, maybe it's time for you to find a new community where you fit in a little bit better. But again, I don't think that this treatment is because of your profession.
|
||||||
|
|
||||||
|
CHARLENE: You might have a point there. I've been thinking about moving my business closer to Flagstaff anyway. My daughter's up there now, just had her second kid. Maybe people up there won't be so sensitive about hearing the truth.
|
||||||
|
|
||||||
|
LUKE: Well, I don't know about that. It's Flagstaff. I think you're probably going to get a lot of people that are very sensitive in that area. But we're going to move on. Mo, Mo, welcome to the show. Thanks for calling in. What's going on tonight.
|
||||||
|
|
||||||
|
MO: Hey, Luke, thanks for taking my call. So I manage a bar down here in O'Gallis, and I just found out my dishwasher is secretly a professional competitive eater. Like I'm watching him on YouTube right now, destroying seven 72 tacos in eight minutes. And I had no idea. This is Danny, the quietest guy on my staff who eats his lunch alone in the alley every single shift.
|
||||||
|
|
||||||
|
LUKE: Does he eat 72 tacos in the alley?
|
||||||
|
|
||||||
|
MO: No, no. He brings like a sandwich or leftovers from home. Just sits out there by the dumpster on his phone, real quiet, comes back in and does his shift. That's what makes this so wild.
|
||||||
|
|
||||||
|
LUKE: One of my regulars came in tonight wearing this gut check championship shirt. asked him about it. And he starts showing me these competitive eating videos on YouTube. And there's Danny. Is Danny super skinny?
|
||||||
|
|
||||||
|
EARL: That's the thing. He's just a normal looking guy. Maybe a little on the thin side, but not like crazy skinny. Which I guess makes sense now that I think about it because these competitive eaters, they're not all big guys. It's about stomach capacity or technique or something.
|
||||||
|
|
||||||
|
LUKE: Yeah, I don't know what it's about, but I mean every competitor of hot dog eating chance, I've ever seen was like ultra skinny. And I always thought that was odd.
|
||||||
|
|
||||||
|
EARL: Right, like you'd think it'd be the opposite. But Danny, he's probably 510, normal build, maybe 160. The crazy part is, on these videos he's got his hair all slick back, and he goes by Daniel Fuentes instead of just Danny. And he's got this whole persona. Like he's intense, focused, the crowd's going nuts. Then he comes in to work the next day, and he's just quiet Danny washing dishes. Won't even make eye contact when you should say good morning.
|
||||||
|
|
||||||
|
LUKE: Well, maybe you guys could lean into that and make Danny a mascot for your restaurant and have people come in and try to compete against him. And he can be the reigning champion, you know, if they can beat Danny, they get the meal for free. I bet it would bring a lot of business.
|
||||||
|
|
||||||
|
EARL: Oh gosh, that's actually a really interesting idea. I mean, we do pretty good business already, but something like that could definitely draw people in. The thing is, I don't know if Danny wants anyone to know about this. He's kept it completely separate from work. Like, he's been with me for almost two years and I had zero clue.
|
||||||
|
|
||||||
|
LUKE: Well, some people are shy like that, but I bet if you talk to him, he'd be happy to tell you about his, uh, his championships.
|
||||||
|
|
||||||
|
EARL: You think so? I mean, maybe you're right. It's just he's so private. Like, I've tried to be friendly, ask him how his weekend was, and he gives me one word answers.
|
||||||
|
|
||||||
|
LUKE: Well, he's a champion, so he doesn't have to respond if he doesn't want to.
|
||||||
|
|
||||||
|
EARL: That's a fair point. I guess I'm sitting here worried about embarrassing the guy, but he's out there winning championships in front of crowds. He's probably proud of it. I'm just not sure how to bring it up without making it weird. Do I just walk up to him Monday and say, Hey, Danny, saw you demolished 72 tacos on YouTube?
|
||||||
|
|
||||||
|
LUKE: That's what I would do, yeah. I'm like, oh, yeah, man, I've seen you destroy those tacos.
|
||||||
|
|
||||||
|
EARL: Yeah, okay, I could do that. Just be straightforward about it.
|
||||||
|
|
||||||
|
LUKE: Yeah, man. All right, good luck with Danny. That's interesting. Congratulations on having a champion in your ranks. Next up, we're going to take one more call. We've got, Roberta. Roberta, welcome to the show. How can we help you tonight?
|
||||||
|
|
||||||
|
ROBERTA: Hey, Luke. So my neighbor Gary thinks I've been breaking into his garage because my garage door opener started opening his door instead of mine.
|
||||||
|
|
||||||
|
LUKE: Instead of or as well as?
|
||||||
|
|
||||||
|
ROBERTA: Instead of, after the power outage last week, my opener stopped working on my door completely. Then I press it and his door goes up across the street. I can see it from my driveway.
|
||||||
|
|
||||||
|
LUKE: How old is your garage door opener? Because I think they fixed that problem like a decade ago. Those infrared codes rotate and you can reprogram them to work on different stuff. I mean, you could even shut off some of those older-style TVs with one.
|
||||||
|
|
||||||
|
ROBERTA: Six years old. And yeah, that is exactly what I tried to explain to Gary. I showed him articles on my phone about frequency resets after power outages.
|
||||||
|
|
||||||
|
LUKE: I don't know, six years, I think they'd have the rotating codes. But yeah, it sounds like you just got to reprogram your remote. That is definitely a security vulnerability, though. And you don't want somebody just showing up and opening your garage door.
|
||||||
|
|
||||||
|
ROBERTA: Right, which is why I went and bought a new opener today. $75 bucks I did not want to spend. But my husband said, just do it and move on. The thing is, Gary will not let this go. He cornered me at the mailboxes this afternoon. He has this look on his face like I am lying to him.
|
||||||
|
|
||||||
|
LUKE: Well, there's no much you can do about that. Gary sounds like an idiot. I think everybody understands the basics of how a garage door opener, at least used to work. And that was a very common thing back of the day. Now, though, I think for the most part, that's resolved.
|
||||||
|
|
||||||
|
ROBERTA: That is what I thought, too. But Derry kept shaking his head at me like I was making the whole thing up, like I have some reason to sneak into his garage. What would I even be doing in there?
|
||||||
|
|
||||||
|
LUKE: I don't know. Maybe Gary's got something to hide going on in his garage. Maybe he's carving up a body and he doesn't want anybody to know.
|
||||||
|
|
||||||
|
ROBERTA: You know what? That would explain why he got so weird about it. He was not just annoyed. He was like, intense about it. Kept asking me if I had been in there. When was I in there? What did I see? I told him I have never set foot in his garage. But he just kept pushing.
|
||||||
|
|
||||||
|
LUKE: Yeah, well, I would leave it alone. I mean, he could be growing pot or doing something, you know, he just doesn't want people to know about. Whatever, everybody's entitled to their privacy. It's not your fault. Your garage door opener opened his garage door. And he's just going to have to get over it. Because you didn't do anything wrong. He didn't do anything wrong. Everybody just has to move on.
|
||||||
|
|
||||||
|
ROBERTA: That is the thing, though. Now, I cannot stop thinking about what he is so worried about me seeing. I mean, I drive past his house every day. His garage door is open half the time when he is working on his truck. But the second, the second. The second my opener accidentally triggers it. Suddenly, he is acting like I committed some crime. And the way he looked at me, Luke.
|
||||||
|
|
||||||
|
LUKE: Well, it is alarming if somebody's opening your door. How do you know it was you?
|
||||||
|
|
||||||
|
ROBERTA: Because it stopped happening after the power company reset everything last week. And my opener stopped working on my own garage, at the same time his, started opening. It is not rocket science. But Gary acts like I am making up this elaborate story to cover something.
|
||||||
|
|
||||||
|
LUKE: Eh, just ignore Gary. He sounds like a pain in the ass. I can go about your life and don't worry about it.
|
||||||
|
|
||||||
|
ROBERTA: You are probably right. My husband said the same thing. Just let it go. But Gary lives three houses down, and I see him every single day. And now every time I pull into my driveway, I can feel him watching from his window. It is making me crazy.
|
||||||
|
|
||||||
|
LUKE: Well, it's a free country, and he's allowed to watch from his window, so you're just going to have to learn to not let that bother you. And keep in mind somebody's watching you, so don't do anything crazy when you're getting out of your car.
|
||||||
|
|
||||||
|
ROBERTA: That is the part that really gets me. I have lived here for six years. I water his plants when he goes out of town. We have borrowed tools back and forth. And now suddenly, I am some suspicious character because of a garage door malfunction.
|
||||||
|
|
||||||
|
LUKE: That's too bad, but I hope that everything works out with you and Gary, and you have a wonderful weekend. Ladies and gentlemen, that's the end of our show. Thank you for tuning in. We'll talk to you again tomorrow night. And hopefully, maybe we'll get some calls that get me less upset, because that would be nice. I felt my blood pressure rising on this one. And that doesn't make any sense, because these aren't even real people. So why am I getting upset with them? I don't know. But hopefully you enjoyed the show. So have a great weekend, and we'll talk to you tomorrow. Bye.
|
||||||