Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
56e44f8
pop up mode and chat buble toggle
pladisdev Nov 2, 2025
82db2b0
potential audio fix
pladisdev Nov 2, 2025
579683d
linux sh and better docker support
pladisdev Nov 2, 2025
fad6d1a
fixed linux build?
pladisdev Nov 2, 2025
a12de82
linux fix part 2
pladisdev Nov 2, 2025
5d79afe
docker fix part 1
pladisdev Nov 2, 2025
0f3af89
Initial plan
Copilot Nov 2, 2025
d5d90f6
Initial plan
Copilot Nov 2, 2025
cbf5fcd
Initial plan
Copilot Nov 2, 2025
5a5d1d5
Initial plan
Copilot Nov 2, 2025
207ba9b
Initial plan
Copilot Nov 2, 2025
76b9912
Initial plan
Copilot Nov 2, 2025
366b640
Initial plan
Copilot Nov 2, 2025
ebc7bb7
Update frontend/src/pages/YappersPage.jsx
pladisdev Nov 2, 2025
be9a086
Initial plan
Copilot Nov 2, 2025
3fc9146
Update frontend/src/pages/YappersPage.jsx
pladisdev Nov 2, 2025
914b789
Replace sys.platform with platform.system() for OS detection
Copilot Nov 2, 2025
938886f
Fix race condition in popup avatar lifecycle
Copilot Nov 2, 2025
7737a2f
Extract magic numbers to named constants for better readability
Copilot Nov 2, 2025
3ea0d45
Extract magic number -2.5px into avatarActiveOffset setting
Copilot Nov 2, 2025
ee4de2a
Fix audio cleanup in popup mode when play() fails
Copilot Nov 2, 2025
3ae0527
Merge pull request #17 from pladisdev/copilot/sub-pr-8-bf786502-ac5d-…
pladisdev Nov 2, 2025
25dc303
Extract hex opacity calculation to utility function
Copilot Nov 2, 2025
730dc88
Fix audio error handlers to clean up tracking references
Copilot Nov 2, 2025
bb266bd
Merge pull request #16 from pladisdev/copilot/sub-pr-8-4be2dd0e-06ec-…
pladisdev Nov 2, 2025
7d70a13
Merge pull request #15 from pladisdev/copilot/sub-pr-8-9e407134-0238-…
pladisdev Nov 2, 2025
d1f450d
Merge pull request #14 from pladisdev/copilot/sub-pr-8-please-work
pladisdev Nov 2, 2025
5436727
Merge pull request #13 from pladisdev/copilot/sub-pr-8-one-more-time
pladisdev Nov 2, 2025
d8c850e
Merge pull request #12 from pladisdev/copilot/sub-pr-8-yet-again
pladisdev Nov 2, 2025
1405787
Merge pull request #11 from pladisdev/copilot/sub-pr-8-another-one
pladisdev Nov 2, 2025
1ad53b1
Merge pull request #10 from pladisdev/copilot/sub-pr-8-again
pladisdev Nov 2, 2025
3956aed
Merge branch 'main' into development
pladisdev Nov 2, 2025
a0b1f82
update flow for builds
pladisdev Nov 2, 2025
a2d0cea
Merge branch 'main' into development
pladisdev Nov 2, 2025
6adf5b1
better build and release file
pladisdev Nov 2, 2025
57df8ef
workflow fix
pladisdev Nov 2, 2025
6bbabff
Merge branch 'main' into development
pladisdev Nov 2, 2025
7672520
build fix
pladisdev Nov 2, 2025
d56e12e
Merge branch 'development' of https://github.com/pladisdev/chat-yappe…
pladisdev Nov 2, 2025
5aca8cf
Merge branch 'main' into development
pladisdev Nov 2, 2025
f0cb455
usernames in chat bubbles
pladisdev Nov 6, 2025
dd0ffab
Merge branch 'development' of https://github.com/pladisdev/chat-yappe…
pladisdev Nov 6, 2025
4f534c8
twitch authentifcation
pladisdev Nov 6, 2025
9095db5
Merge branch 'main' into development
pladisdev Nov 6, 2025
979acca
tts limit
pladisdev Nov 22, 2025
008f0e0
notifcation that user needs to click page, quick status
pladisdev Nov 22, 2025
c09bdcc
update readme, version
pladisdev Nov 22, 2025
1cb53f6
Merge branch 'main' into development
pladisdev Nov 22, 2025
ee60426
emergency twitch fix
pladisdev Nov 22, 2025
56967e2
Merge branch 'main' into development
pladisdev Nov 22, 2025
cfcf2dd
Merge branch 'main' into development
pladisdev Nov 22, 2025
1aa6813
yep
pladisdev Nov 22, 2025
5844084
dang
pladisdev Nov 22, 2025
4a6a8e5
better twitch logging
pladisdev Nov 23, 2025
693bfbc
animations and avatar layout editor
pladisdev Nov 23, 2025
326928e
fix spin animation
pladisdev Nov 23, 2025
a80e583
twitch fix part 2
pladisdev Nov 23, 2025
69800d3
Merge branch 'main' into development
pladisdev Nov 23, 2025
365ef8e
twitch fix, better fonts, cleanup
pladisdev Nov 25, 2025
61d9dcf
Merge branch 'main' into development
pladisdev Nov 25, 2025
046c52f
fixed imports
pladisdev Nov 25, 2025
7b33d13
fixed things
pladisdev Nov 25, 2025
638fb4e
Merge branch 'main' into development
pladisdev Nov 25, 2025
59a7722
undefined fix
pladisdev Nov 25, 2025
4a09f0b
twitch test fix
pladisdev Nov 25, 2025
99b9642
another mock fix
pladisdev Nov 25, 2025
15efb3c
another fix for twitch creds tests
pladisdev Nov 25, 2025
6ca3832
better logging
pladisdev Nov 25, 2025
08355e7
twitch fixes?
pladisdev Nov 25, 2025
0d7bb86
another twitch fix
pladisdev Nov 25, 2025
484caaf
Merge branch 'main' into development
pladisdev Nov 25, 2025
a45dcfc
fix twitch io 3.x
pladisdev Nov 25, 2025
478e8ea
Merge branch 'development' of https://github.com/pladisdev/chat-yappe…
pladisdev Nov 25, 2025
6ad992d
fix pipelines for python to use 3.10
pladisdev Nov 25, 2025
2fcaa47
Merge branch 'main' into development
pladisdev Nov 25, 2025
4e39aa1
attempt to fix edge tts
pladisdev Feb 14, 2026
01b85b8
fixed build and release
pladisdev Feb 14, 2026
7a1ee84
annother wix fix
pladisdev Feb 14, 2026
8589ceb
global wix fix
pladisdev Feb 14, 2026
0f9441b
Merge branch 'main' into development
pladisdev Feb 14, 2026
ca487ed
update to edge-tts
pladisdev Apr 5, 2026
a7b0ddf
Merge branch 'development' of https://github.com/pladisdev/chat-yappe…
pladisdev Apr 5, 2026
9a96471
update to new version
pladisdev Apr 5, 2026
dc502bd
redeem fix, new effects, @filter
pladisdev Apr 7, 2026
3646a03
Merge branch 'main' into development
pladisdev Apr 7, 2026
f8f4f78
added new test
pladisdev Apr 7, 2026
3766fed
fix to redeems, new auth
pladisdev Apr 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build-and-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ jobs:
docker-build:
name: Build and Push Docker Image
runs-on: ubuntu-latest
if: false # Disabled - Docker build step is commented out; re-enable when build-push-action is restored
continue-on-error: true
needs: build # Run after Windows build succeeds

Expand Down
67 changes: 67 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Changelog

All notable changes to Chat Yapper are documented here.

## v1.3.3 (Latest)
- twitch redeem fix
- two new voice effects
- new filter for @user messages

## v1.3.2
- Fix to edge-tts

## v1.3.1
- **New Features:**
- Twitch fix
- Allow random avatar assignment
- More fonts to select from

## v1.3.0
- Better control of avatar placement in Avatar Layout Editor
- Select and Adjust speaking animations for crowd mode
- Added idle animations for crowd mode

## v1.2.2
- Quick status view
- Limit concurrent TTS messages
- Some more twitch fixes and improved notifications

## v1.2.1
- Usernames for chat bubbles
- Text size adjustment
- Toggle for only allowing redeem messages for Twitch
- Twitch token refresh (should fix auth issues)

## v1.2.0
- Chat bubbles above avatars
- Pop-up mode for avatars
- Linux standalone build (x64)
- Improved audio quality (reduced crackling)
- Docker multi-architecture support (amd64, arm64)
- Better audio preloading and buffering
- High-quality ffmpeg audio processing
- GitHub Container Registry (GHCR) for Docker images
- Automated cross-platform builds via GitHub Actions

## v1.1.2
- Stability fixes
- MSI installation for Windows
- Light mode theme
- Cleaned up settings UI

## v1.0.0
- GIF and WebP support for animated avatars
- Customizable speaking glow effects (color, opacity, size, enable/disable)
- Message history and replay system (stores 100 recent messages)
- Export/Import configuration system (backup/restore settings, voices, and avatars)
- Persistent voice caching for all TTS providers (MonsterTTS, Google Cloud, Amazon Polly, Edge TTS)
- Audio filters
- Docker Support

## v0.1.0
- Initial release
- Avatars page
- Settings page
- TTS selection
- Avatar positioning
- Basic Twitch integration
60 changes: 2 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,64 +225,7 @@ chat-yapper/

## Changelog

### v1.3.2 (Latest)
- Fix to edge-tts

### v1.3.1
- **New Features:**
- Twitch fix
- Allow random avatar assignment
- More fonts to select from

### v1.3.0
- Better control of avatar placement in Avatar Layout Editor
- Select and Adjust speaking animations for crowd mode
- Added idle animations for crowd mode

### v1.2.2
- Quick status view
- Limit concurrent TTS messages
- Some more twitch fixes and improved notifcations

### v1.2.1
- usernames for chatbubbles
- text size adjustment
- Toggle for only allowing redeem messages for twitch
- twitch token refresh (should fix auth issues)

### v1.2.0
- Chat bubbles above avatars
- Pop-up mode for avatars
- Linux standalone build (x64)
- Improved audio quality (reduced crackling)
- Docker multi-architecture support (amd64, arm64)
- Better audio preloading and buffering
- High-quality ffmpeg audio processing
- GitHub Container Registry (GHCR) for Docker images
- Automated cross-platform builds via GitHub Actions

### v1.1.2
- Stability fixes
- MSI installation for Windows
- Light mode theme
- Cleaned up settings UI

### v1.0.0
- GIF and WebP support for animated avatars
- Customizable speaking glow effects (color, opacity, size, enable/disable)
- Message history and replay system (stores 100 recent messages)
- Export/Import configuration system (backup/restore settings, voices, and avatars)
- Persistent voice caching for all TTS providers (MonsterTTS, Google Cloud, Amazon Polly, Edge TTS)
- Audio filters
- Docker Support

### v0.1.0
- Initial release
- Avatars page
- Settings page
- TTS selection
- Avatar positioning
- Basic Twitch integration
See [CHANGELOG.md](CHANGELOG.md) for the full version history.

---

Expand Down Expand Up @@ -319,6 +262,7 @@ This application was inspired by the work done by [shindigs](https://x.com/shind
Special thanks these streamers that helped test the early prototype:
- [**Inislein**](https://x.com/iniskein)
- [**Kirana**](https://x.com/KiranaYonome)
- [**Miaelou**](https://x.com/Miaelou_VT)

---

Expand Down
47 changes: 45 additions & 2 deletions backend/modules/audio_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ def _has_enabled_filters(self, settings: Dict[str, Any]) -> bool:
settings.get("reverb", {}).get("enabled", False),
settings.get("pitch", {}).get("enabled", False),
settings.get("speed", {}).get("enabled", False),
settings.get("underwater", {}).get("enabled", False),
settings.get("vibrato", {}).get("enabled", False),
])

def _build_filters(self, settings: Dict[str, Any]) -> List[str]:
Expand Down Expand Up @@ -212,7 +214,27 @@ def _build_filters(self, settings: Dict[str, Any]) -> List[str]:
else: # speed > 2.0
# Chain multiple atempo for very fast speeds
filters.append(f"atempo=2.0,atempo={speed/2.0}")


# Underwater effect
# Technique: low-pass filter (water absorbs high freqs) + echo (watery reverb) + chorus (wobbly sub-surface)
if settings.get("underwater", {}).get("enabled", False):
intensity = settings.get("underwater", {}).get("intensity", 50) # 0-100
# Map intensity to low-pass cutoff: 0% = 1200 Hz (shallow), 100% = 500 Hz (deep)
freq = int(1200 - (intensity / 100.0) * 700)
filters.append(
f"lowpass=f={freq},"
f"aecho=0.8:0.88:60|80:0.5|0.4,"
f"chorus=0.7:0.9:55|60:0.4|0.35:0.25|0.4:2|1.3"
)

# Vibrato effect: periodic pitch modulation
if settings.get("vibrato", {}).get("enabled", False):
rate = settings.get("vibrato", {}).get("rate", 10.0) # Hz, 6.0-15.0
depth = settings.get("vibrato", {}).get("depth", 75) / 100.0 # 0.0-1.0
rate = max(0.1, min(20.0, float(rate)))
depth = max(0.0, min(1.0, depth))
filters.append(f"vibrato=f={rate:.1f}:d={depth:.2f}")

return filters

def _build_random_filters(self, settings: Dict[str, Any]) -> List[str]:
Expand All @@ -228,6 +250,11 @@ def _build_random_filters(self, settings: Dict[str, Any]) -> List[str]:
if settings.get("speed", {}).get("randomEnabled", True):
available_filters.append("speed")

if settings.get("underwater", {}).get("randomEnabled", True):
available_filters.append("underwater")
if settings.get("vibrato", {}).get("randomEnabled", True):
available_filters.append("vibrato")

if not available_filters:
logger.warning("No effects enabled for random mode")
return filters
Expand All @@ -239,7 +266,23 @@ def _build_random_filters(self, settings: Dict[str, Any]) -> List[str]:
selected = random.sample(available_filters, num_filters)

for filter_type in selected:
if filter_type == "reverb":
if filter_type == "underwater":
intensity = random.randint(30, 80)
freq = int(1200 - (intensity / 100.0) * 700)
filters.append(
f"lowpass=f={freq},"
f"aecho=0.8:0.88:60|80:0.5|0.4,"
f"chorus=0.7:0.9:55|60:0.4|0.35:0.25|0.4:2|1.3"
)
logger.debug(f"Random underwater: intensity={intensity}% (cutoff={freq} Hz)")

elif filter_type == "vibrato":
rate = round(random.uniform(6.0, 15.0), 1)
depth = round(random.uniform(0.5, 1.0), 2)
filters.append(f"vibrato=f={rate}:d={depth}")
logger.debug(f"Random vibrato: rate={rate} Hz, depth={depth}")

elif filter_type == "reverb":
# Get custom range or use defaults
reverb_config = settings.get("reverb", {})
random_range = reverb_config.get("randomRange", {"min": 20, "max": 80})
Expand Down
65 changes: 41 additions & 24 deletions backend/modules/message_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,33 +138,44 @@ def should_process_message(
Returns:
(should_process, filtered_text) - tuple indicating if message should be processed and the filtered text
"""
filtering = settings.get("messageFiltering", {})

if not filtering.get("enabled", True):
return True, text

# Check Twitch channel point redeem filter
# Check Twitch channel point redeem filter first — this applies regardless of
# whether general message filtering is enabled or disabled.
twitch_settings = settings.get("twitch", {})
redeem_filter = twitch_settings.get("redeemFilter", {})
if redeem_filter.get("enabled", False):
allowed_redeem_names = redeem_filter.get("allowedRedeemNames", [])
if allowed_redeem_names:
# Check if message has a msg-param-reward-name tag (the redeem name)
# Also check custom-reward-id to confirm it's a redeem
custom_reward_id = tags.get("custom-reward-id", "") if tags else ""
reward_name = tags.get("msg-param-reward-name", "") if tags else ""

if not custom_reward_id:
# No redeem ID means this is a regular message, not a channel point redeem
logger.info(f"Skipping message from {username} - not from a channel point redeem")
return False, text

# Check if the redeem name is in the allowed list (case-insensitive)
if not any(reward_name.lower() == allowed_name.lower() for allowed_name in allowed_redeem_names):
logger.info(f"Skipping message from {username} - redeem name '{reward_name}' not in allowed list")
return False, text

logger.info(f"Processing message from {username} - redeem name '{reward_name}' is allowed")
# Twitch IRC PRIVMSG tags include custom-reward-id (UUID) for channel point redeems,
# but do NOT include the reward title/name.
# Exception: the built-in "Highlight My Message" reward uses msg-id=highlighted-message
# instead of custom-reward-id, so we treat that as a valid redeem with the
# identifier "highlighted-message".
custom_reward_id = (tags.get("custom-reward-id", "") or "") if tags else ""
msg_id = (tags.get("msg-id", "") or "") if tags else ""
is_highlight = msg_id.lower() == "highlighted-message"
redeem_identifier = custom_reward_id or ("highlighted-message" if is_highlight else "")

if not redeem_identifier:
# No redeem ID means this is a regular chat message, not a channel point redeem
logger.info(f"Skipping message from {username} - not from a channel point redeem")
return False, text

allowed_redeem_names = redeem_filter.get("allowedRedeemNames", []) or []
normalized_allowed = {
str(r).strip().lower()
for r in allowed_redeem_names
if str(r).strip()
}
if normalized_allowed and redeem_identifier.lower() not in normalized_allowed:
logger.info(
f"Skipping channel point redeem from {username} - reward ID not in allowlist: {redeem_identifier}"
)
return False, text

logger.info(f"Processing channel point redeem from {username} (reward-id: {redeem_identifier})")

filtering = settings.get("messageFiltering", {})

if not filtering.get("enabled", True):
return True, text

# Skip ignored users
if username and filtering.get("ignoredUsers"):
Expand All @@ -180,6 +191,12 @@ def should_process_message(
if stripped.startswith('!') or stripped.startswith('/'):
logger.info(f"Skipping command message: {text[:50]}...")
return False, text

# Skip messages that @mention someone
if filtering.get("skipMentions", False):
if re.search(r'@\w+', text):
logger.info(f"Skipping mention message from {username}: {text[:50]}...")
return False, text
Comment on lines 141 to +199
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New skipMentions filtering and the updated Twitch redeem handling are not covered by unit tests. There are existing pytest tests for this module, but none exercise should_process_message(). Adding tests for (a) redeemFilter enabled/disabled with/without custom-reward-id/highlighted-message, and (b) skipMentions on/off would help prevent regressions.

Copilot uses AI. Check for mistakes.

# Start with original text, apply filters progressively
filtered_text = text
Expand Down
2 changes: 1 addition & 1 deletion backend/modules/persistent_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def get_user_data_dir():
TWITCH_CLIENT_ID = get_env_var("TWITCH_CLIENT_ID", "pker88pnps6l8ku90u7ggwvt9dmz2f")
TWITCH_CLIENT_SECRET = get_env_var("TWITCH_CLIENT_SECRET", "")
TWITCH_REDIRECT_URI = f"http://localhost:{os.environ.get('PORT', 8000)}/auth/twitch/callback"
TWITCH_SCOPE = "chat:read"
TWITCH_SCOPE = "chat:read channel:read:redemptions"

# YouTube OAuth Configuration
YOUTUBE_CLIENT_ID = get_env_var("YOUTUBE_CLIENT_ID", "")
Expand Down
12 changes: 12 additions & 0 deletions backend/modules/settings_defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"minLength": 1,
"maxLength": 500,
"skipCommands": true,
"skipMentions": false,
"skipEmotes": false,
"removeUrls": true,
"ignoredUsers": [],
Expand Down Expand Up @@ -118,6 +119,17 @@
"min": 0.75,
"max": 1.3
}
},
"underwater": {
"enabled": false,
"intensity": 50,
"randomEnabled": true
},
"vibrato": {
"enabled": false,
"rate": 10.0,
"depth": 75,
"randomEnabled": true
}
}
}
Loading
Loading