2024-06-24 18:11:36 -04:00
using System.Reflection ;
2024-07-06 23:42:33 -04:00
using CommonSocketLibrary.Abstract ;
using CommonSocketLibrary.Common ;
2024-07-16 00:48:55 -04:00
using HermesSocketLibrary.Requests.Messages ;
2024-07-06 23:42:33 -04:00
using Microsoft.Extensions.DependencyInjection ;
2024-06-24 18:11:36 -04:00
using org.mariuszgromada.math.mxparser ;
using Serilog ;
2024-11-08 10:32:42 -05:00
using TwitchChatTTS.Bus ;
using TwitchChatTTS.Bus.Data ;
2024-07-19 12:56:41 -04:00
using TwitchChatTTS.OBS.Socket ;
2024-06-24 18:11:36 -04:00
using TwitchChatTTS.OBS.Socket.Data ;
2024-12-02 15:51:04 -05:00
using TwitchChatTTS.Veadotube ;
2024-06-24 18:11:36 -04:00
namespace TwitchChatTTS.Twitch.Redemptions
{
2024-08-06 15:29:29 -04:00
public class RedemptionManager : IRedemptionManager
2024-06-24 18:11:36 -04:00
{
2025-01-06 09:36:54 -05:00
private readonly IDictionary < string , RedeemableAction > _actions ;
private readonly IDictionary < string , Redemption > _redemptions ;
// twitch redemption id -> redemption ids
private readonly IDictionary < string , IList < string > > _redeems ;
2024-11-08 10:32:42 -05:00
private readonly ServiceBusCentral _bus ;
2024-07-06 23:42:33 -04:00
private readonly User _user ;
2024-07-19 12:56:41 -04:00
private readonly OBSSocketClient _obs ;
2024-12-02 15:51:04 -05:00
private readonly VeadoSocketClient _veado ;
2024-08-11 17:22:37 -04:00
private readonly NightbotApiClient _nightbot ;
2024-08-04 19:46:10 -04:00
private readonly AudioPlaybackEngine _playback ;
2024-06-24 18:11:36 -04:00
private readonly ILogger _logger ;
2024-07-06 23:42:33 -04:00
private readonly Random _random ;
2025-01-06 09:36:54 -05:00
private readonly object _lock ;
2024-06-24 18:11:36 -04:00
2024-07-06 23:42:33 -04:00
public RedemptionManager (
2024-11-08 10:32:42 -05:00
ServiceBusCentral bus ,
2024-07-06 23:42:33 -04:00
User user ,
2024-07-19 12:56:41 -04:00
[FromKeyedServices("obs")] SocketClient < WebSocketMessage > obs ,
2024-12-02 15:51:04 -05:00
[FromKeyedServices("veadotube")] SocketClient < object > veado ,
2024-08-11 17:22:37 -04:00
NightbotApiClient nightbot ,
2024-08-04 19:46:10 -04:00
AudioPlaybackEngine playback ,
2024-07-06 23:42:33 -04:00
ILogger logger )
2024-06-24 18:11:36 -04:00
{
2025-01-06 09:36:54 -05:00
_actions = new Dictionary < string , RedeemableAction > ( ) ;
_redemptions = new Dictionary < string , Redemption > ( ) ;
_redeems = new Dictionary < string , IList < string > > ( ) ;
2024-11-08 10:32:42 -05:00
_bus = bus ;
2024-07-06 23:42:33 -04:00
_user = user ;
2024-07-19 12:56:41 -04:00
_obs = ( obs as OBSSocketClient ) ! ;
2024-12-02 15:51:04 -05:00
_veado = ( veado as VeadoSocketClient ) ! ;
2024-08-11 17:22:37 -04:00
_nightbot = nightbot ;
2024-08-04 19:46:10 -04:00
_playback = playback ;
2024-06-24 18:11:36 -04:00
_logger = logger ;
2024-07-06 23:42:33 -04:00
_random = new Random ( ) ;
2025-01-06 09:36:54 -05:00
_lock = new object ( ) ;
2024-11-08 10:32:42 -05:00
var topic = _bus . GetTopic ( "redemptions_initiation" ) ;
2025-01-07 10:42:10 -05:00
topic . Subscribe ( data = >
2024-12-02 21:39:27 -05:00
{
2025-01-06 09:36:54 -05:00
if ( data . Value is not RedemptionInitiation init )
return ;
if ( init . Actions = = null )
init . Actions = new Dictionary < string , RedeemableAction > ( ) ;
if ( init . Redemptions = = null )
init . Redemptions = new List < Redemption > ( ) ;
if ( ! init . Actions . Any ( ) )
_logger . Warning ( "No redeemable actions were loaded." ) ;
if ( ! init . Redemptions . Any ( ) )
_logger . Warning ( "No redemptions were loaded." ) ;
foreach ( var action in init . Actions . Values )
Add ( action ) ;
foreach ( var redemption in init . Redemptions )
Add ( redemption ) ;
Initialize ( ) ;
2025-01-07 10:42:10 -05:00
} ) ;
2024-06-24 18:11:36 -04:00
}
2025-01-06 09:36:54 -05:00
public void Add ( RedeemableAction action )
2024-06-24 18:11:36 -04:00
{
2025-01-06 09:36:54 -05:00
if ( ! _actions . ContainsKey ( action . Name ) )
{
_actions . Add ( action . Name , action ) ;
_logger . Debug ( $"Added redeemable action to redemption manager [action name: {action.Name}]" ) ;
}
else
_logger . Debug ( $"Redemption manager already has this action stored [action name: {action.Name}]" ) ;
}
2024-07-06 23:42:33 -04:00
2025-01-06 09:36:54 -05:00
public void Add ( Redemption redemption )
{
_redemptions . Add ( redemption . Id , redemption ) ;
Add ( redemption . TwitchRedemptionId , redemption ) ;
}
private void Add ( string twitchRedemptionId , string redemptionId )
{
lock ( _lock )
{
if ( ! _redeems . TryGetValue ( twitchRedemptionId , out var redeems ) )
_redeems . Add ( twitchRedemptionId , redeems = new List < string > ( ) ) ;
var item = _redemptions . TryGetValue ( redemptionId , out var r ) ? r : null ;
if ( item = = null )
{
return ;
}
var redemptions = redeems . Select ( r = > _redemptions . TryGetValue ( r , out var rr ) ? rr : null ) ;
bool added = false ;
for ( int i = 0 ; i < redeems . Count ; i + + )
{
if ( redeems [ i ] ! = null & & _redemptions . TryGetValue ( redeems [ i ] , out var rr ) )
{
if ( item . Order > rr . Order )
{
redeems . Insert ( i , redemptionId ) ;
added = true ;
break ;
}
}
}
if ( ! added )
redeems . Add ( redemptionId ) ;
}
_logger . Debug ( $"Added redemption action [redemption id: {redemptionId}][twitch redemption id: {twitchRedemptionId}]" ) ;
}
private void Add ( string twitchRedemptionId , Redemption item )
{
lock ( _lock )
{
if ( ! _redeems . TryGetValue ( twitchRedemptionId , out var redemptionNames ) )
_redeems . Add ( twitchRedemptionId , redemptionNames = new List < string > ( ) ) ;
var redemptions = redemptionNames . Select ( r = > _redemptions . TryGetValue ( r , out var rr ) ? rr : null ) ;
bool added = false ;
for ( int i = 0 ; i < redemptionNames . Count ; i + + )
{
if ( redemptionNames [ i ] ! = null & & _redemptions . TryGetValue ( redemptionNames [ i ] , out var rr ) )
{
if ( item . Order > rr . Order )
{
redemptionNames . Insert ( i , item . Id ) ;
added = true ;
break ;
}
}
}
if ( ! added )
redemptionNames . Add ( item . Id ) ;
}
_logger . Debug ( $"Added redemption action [redemption id: {item.Id}][twitch redemption id: {twitchRedemptionId}]" ) ;
2024-06-24 18:11:36 -04:00
}
2024-07-06 23:42:33 -04:00
public async Task Execute ( RedeemableAction action , string senderDisplayName , long senderId )
2024-06-24 18:11:36 -04:00
{
2024-07-16 00:48:55 -04:00
_logger . Debug ( $"Executing an action for a redemption [action: {action.Name}][action type: {action.Type}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
if ( action . Data = = null )
{
_logger . Warning ( $"No data was provided for an action, caused by redemption [action: {action.Name}][action type: {action.Type}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
return ;
}
2024-06-24 18:11:36 -04:00
try
{
switch ( action . Type )
{
case "WRITE_TO_FILE" :
2024-12-28 16:19:28 -05:00
Directory . CreateDirectory ( Path . GetDirectoryName ( action . Data [ "file_path" ] ) ! ) ;
2024-07-06 23:42:33 -04:00
await File . WriteAllTextAsync ( action . Data [ "file_path" ] , ReplaceContentText ( action . Data [ "file_content" ] , senderDisplayName ) ) ;
2024-07-16 00:48:55 -04:00
_logger . Debug ( $"Overwritten text to file [file: {action.Data[" file_path "]}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-06-24 18:11:36 -04:00
break ;
case "APPEND_TO_FILE" :
2024-12-28 16:19:28 -05:00
Directory . CreateDirectory ( Path . GetDirectoryName ( action . Data [ "file_path" ] ) ! ) ;
2024-07-06 23:42:33 -04:00
await File . AppendAllTextAsync ( action . Data [ "file_path" ] , ReplaceContentText ( action . Data [ "file_content" ] , senderDisplayName ) ) ;
2024-07-16 00:48:55 -04:00
_logger . Debug ( $"Appended text to file [file: {action.Data[" file_path "]}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-06-24 18:11:36 -04:00
break ;
case "OBS_TRANSFORM" :
var type = typeof ( OBSTransformationData ) ;
2024-07-19 12:56:41 -04:00
await _obs . UpdateTransformation ( action . Data [ "scene_name" ] , action . Data [ "scene_item_name" ] , ( d ) = >
2024-06-24 18:11:36 -04:00
{
string [ ] properties = [ "rotation" , "position_x" , "position_y" ] ;
foreach ( var property in properties )
{
if ( ! action . Data . TryGetValue ( property , out var expressionString ) | | expressionString = = null )
continue ;
var propertyName = string . Join ( "" , property . Split ( '_' ) . Select ( p = > char . ToUpper ( p [ 0 ] ) + p . Substring ( 1 ) ) ) ;
PropertyInfo ? prop = type . GetProperty ( propertyName , BindingFlags . Public | BindingFlags . Instance ) ;
if ( prop = = null )
{
2024-07-16 00:48:55 -04:00
_logger . Warning ( $"Failed to find property for OBS transformation [scene: {action.Data[" scene_name "]}][source: {action.Data[" scene_item_name "]}][property: {propertyName}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-06-24 18:11:36 -04:00
continue ;
}
var currentValue = prop . GetValue ( d ) ;
if ( currentValue = = null )
{
2024-07-16 00:48:55 -04:00
_logger . Warning ( $"Found a null value from OBS transformation [scene: {action.Data[" scene_name "]}][source: {action.Data[" scene_item_name "]}][property: {propertyName}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
continue ;
2024-06-24 18:11:36 -04:00
}
Expression expression = new Expression ( expressionString ) ;
expression . addConstants ( new Constant ( "x" , ( double? ) currentValue ? ? 0.0d ) ) ;
if ( ! expression . checkSyntax ( ) )
{
2024-07-16 00:48:55 -04:00
_logger . Warning ( $"Could not parse math expression for OBS transformation [scene: {action.Data[" scene_name "]}][source: {action.Data[" scene_item_name "]}][expression: {expressionString}][property: {propertyName}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-06-24 18:11:36 -04:00
continue ;
}
var newValue = expression . calculate ( ) ;
prop . SetValue ( d , newValue ) ;
2024-07-16 00:48:55 -04:00
_logger . Debug ( $"OBS transformation [scene: {action.Data[" scene_name "]}][source: {action.Data[" scene_item_name "]}][property: {propertyName}][old value: {currentValue}][new value: {newValue}][expression: {expressionString}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-06-24 18:11:36 -04:00
}
2024-07-16 00:48:55 -04:00
_logger . Debug ( $"Finished applying the OBS transformation property changes [scene: {action.Data[" scene_name "]}][source: {action.Data[" scene_item_name "]}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-06-24 18:11:36 -04:00
} ) ;
break ;
2024-07-06 23:42:33 -04:00
case "TOGGLE_OBS_VISIBILITY" :
2024-07-19 12:56:41 -04:00
await _obs . ToggleSceneItemVisibility ( action . Data [ "scene_name" ] , action . Data [ "scene_item_name" ] ) ;
2024-07-06 23:42:33 -04:00
break ;
case "SPECIFIC_OBS_VISIBILITY" :
2024-07-19 12:56:41 -04:00
await _obs . UpdateSceneItemVisibility ( action . Data [ "scene_name" ] , action . Data [ "scene_item_name" ] , action . Data [ "obs_visible" ] . ToLower ( ) = = "true" ) ;
2024-07-06 23:42:33 -04:00
break ;
case "SPECIFIC_OBS_INDEX" :
2024-07-19 12:56:41 -04:00
await _obs . UpdateSceneItemIndex ( action . Data [ "scene_name" ] , action . Data [ "scene_item_name" ] , int . Parse ( action . Data [ "obs_index" ] ) ) ;
2024-07-06 23:42:33 -04:00
break ;
case "SLEEP" :
_logger . Debug ( "Sleeping on thread due to redemption for OBS." ) ;
await Task . Delay ( int . Parse ( action . Data [ "sleep" ] ) ) ;
break ;
case "SPECIFIC_TTS_VOICE" :
2024-07-16 00:48:55 -04:00
case "RANDOM_TTS_VOICE" :
string voiceId = string . Empty ;
bool specific = action . Type = = "SPECIFIC_TTS_VOICE" ;
var voicesEnabled = _user . VoicesEnabled . ToList ( ) ;
if ( specific )
voiceId = _user . VoicesAvailable . Keys . First ( id = > _user . VoicesAvailable [ id ] . ToLower ( ) = = action . Data [ "tts_voice" ] . ToLower ( ) ) ;
else
{
if ( ! voicesEnabled . Any ( ) )
{
_logger . Warning ( $"There are no TTS voices enabled [voice pool size: {voicesEnabled.Count}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
return ;
}
if ( voicesEnabled . Count < = 1 )
{
_logger . Warning ( $"There are not enough TTS voices enabled to randomize [voice pool size: {voicesEnabled.Count}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
return ;
}
string? selectedId = null ;
if ( ! _user . VoicesSelected . ContainsKey ( senderId ) )
selectedId = _user . VoicesAvailable . Keys . First ( id = > _user . VoicesAvailable [ id ] = = _user . DefaultTTSVoice ) ;
else
selectedId = _user . VoicesSelected [ senderId ] ;
do
{
var randomVoice = voicesEnabled [ _random . Next ( voicesEnabled . Count ) ] ;
voiceId = _user . VoicesAvailable . Keys . First ( id = > _user . VoicesAvailable [ id ] = = randomVoice ) ;
} while ( voiceId = = selectedId ) ;
}
if ( string . IsNullOrEmpty ( voiceId ) )
2024-07-06 23:42:33 -04:00
{
2024-07-16 00:48:55 -04:00
_logger . Warning ( $"Voice is not valid [voice: {action.Data[" tts_voice "]}][voice pool size: {voicesEnabled.Count}][source: redemption][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-07-06 23:42:33 -04:00
return ;
}
var voiceName = _user . VoicesAvailable [ voiceId ] ;
if ( ! _user . VoicesEnabled . Contains ( voiceName ) )
{
2024-07-16 00:48:55 -04:00
_logger . Warning ( $"Voice is not enabled [voice: {action.Data[" tts_voice "]}][voice pool size: {voicesEnabled.Count}][voice id: {voiceId}][source: redemption][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-07-06 23:42:33 -04:00
return ;
}
2024-07-16 00:48:55 -04:00
if ( _user . VoicesSelected . ContainsKey ( senderId ) )
2024-07-06 23:42:33 -04:00
{
2025-01-07 10:30:13 -05:00
_bus . Send ( this , "tts.user.voice.update" , new Dictionary < string , object > ( ) { { "chatter" , senderId } , { "voice" , voiceId } } ) ;
2024-12-28 16:19:28 -05:00
_logger . Debug ( $"Sent request to update chat TTS voice [voice: {voiceName}][chatter id: {senderId}][source: redemption][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-07-06 23:42:33 -04:00
}
2024-07-16 00:48:55 -04:00
else
2024-07-06 23:42:33 -04:00
{
2025-01-07 10:30:13 -05:00
_bus . Send ( this , "tts.user.voice.create" , new Dictionary < string , object > ( ) { { "chatter" , senderId } , { "voice" , voiceId } } ) ;
2024-12-28 16:19:28 -05:00
_logger . Debug ( $"Sent request to create chat TTS voice [voice: {voiceName}][chatter id: {senderId}][source: redemption][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-07-06 23:42:33 -04:00
}
break ;
2024-06-24 18:11:36 -04:00
case "AUDIO_FILE" :
2024-07-06 23:42:33 -04:00
if ( ! File . Exists ( action . Data [ "file_path" ] ) )
{
2024-07-16 00:48:55 -04:00
_logger . Warning ( $"Cannot find audio file for Twitch channel point redeem [file: {action.Data[" file_path "]}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-06-24 18:11:36 -04:00
return ;
}
2024-08-04 19:46:10 -04:00
_playback . PlaySound ( action . Data [ "file_path" ] ) ;
2024-07-16 00:48:55 -04:00
_logger . Debug ( $"Played an audio file for channel point redeem [file: {action.Data[" file_path "]}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-06-24 18:11:36 -04:00
break ;
2024-08-11 17:22:37 -04:00
case "NIGHTBOT_PLAY" :
await _nightbot . Play ( ) ;
break ;
case "NIGHTBOT_PAUSE" :
await _nightbot . Pause ( ) ;
break ;
case "NIGHTBOT_SKIP" :
await _nightbot . Skip ( ) ;
break ;
case "NIGHTBOT_CLEAR_PLAYLIST" :
await _nightbot . ClearPlaylist ( ) ;
break ;
case "NIGHTBOT_CLEAR_QUEUE" :
await _nightbot . ClearQueue ( ) ;
break ;
2024-12-02 15:51:04 -05:00
case "VEADOTUBE_SET_STATE" :
2024-12-02 21:39:27 -05:00
{
var state = _veado . GetStateId ( action . Data [ "state" ] ) ;
2025-01-06 09:36:54 -05:00
if ( state = = null )
{
2024-12-02 21:39:27 -05:00
_logger . Warning ( $"Could not find the state named '{action.Data[" state "]}'." ) ;
break ;
}
await _veado . SetCurrentState ( state ) ;
break ;
}
2024-12-02 15:51:04 -05:00
case "VEADOTUBE_PUSH_STATE" :
2024-12-02 21:39:27 -05:00
{
var state = _veado . GetStateId ( action . Data [ "state" ] ) ;
2025-01-06 09:36:54 -05:00
if ( state = = null )
{
2024-12-02 21:39:27 -05:00
_logger . Warning ( $"Could not find the state named '{action.Data[" state "]}'." ) ;
break ;
}
await _veado . PushState ( state ) ;
break ;
}
2024-12-02 15:51:04 -05:00
case "VEADOTUBE_POP_STATE" :
2024-12-02 21:39:27 -05:00
{
var state = _veado . GetStateId ( action . Data [ "state" ] ) ;
2025-01-06 09:36:54 -05:00
if ( state = = null )
{
2024-12-02 21:39:27 -05:00
_logger . Warning ( $"Could not find the state named '{action.Data[" state "]}'." ) ;
break ;
}
await _veado . PopState ( state ) ;
break ;
}
2024-06-24 18:11:36 -04:00
default :
2025-01-06 09:36:54 -05:00
_logger . Warning ( $"Unknown redeemable action has occured [type: {action.Type}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-06-24 18:11:36 -04:00
break ;
}
}
catch ( Exception ex )
{
2024-07-16 00:48:55 -04:00
_logger . Error ( ex , $"Failed to execute a redemption action [action: {action.Name}][action type: {action.Type}][chatter: {senderDisplayName}][chatter id: {senderId}]" ) ;
2024-06-24 18:11:36 -04:00
}
}
2025-01-06 09:36:54 -05:00
public IEnumerable < RedeemableAction > Get ( string twitchRedemptionId )
2024-06-24 18:11:36 -04:00
{
2025-01-06 09:36:54 -05:00
lock ( _lock )
{
if ( _redeems . TryGetValue ( twitchRedemptionId , out var redemptionIds ) )
return redemptionIds . Select ( r = > _redemptions . TryGetValue ( r , out var redemption ) ? redemption : null )
. Where ( r = > r ! = null )
. Select ( r = > _actions . TryGetValue ( r ! . ActionName , out var action ) ? action : null )
. Where ( a = > a ! = null ) ! ;
}
return [ ] ;
2024-06-24 18:11:36 -04:00
}
2025-01-06 09:36:54 -05:00
public void Initialize ( )
2024-06-24 18:11:36 -04:00
{
2025-01-06 09:36:54 -05:00
_logger . Debug ( $"Redemption manager is about to initialize [redemption count: {_redemptions.Count()}][action count: {_actions.Count}]" ) ;
2024-06-24 18:11:36 -04:00
2025-01-06 09:36:54 -05:00
lock ( _lock )
2024-07-06 23:42:33 -04:00
{
2025-01-06 09:36:54 -05:00
_redeems . Clear ( ) ;
2024-07-16 00:48:55 -04:00
2025-01-06 09:36:54 -05:00
var ordered = _redemptions . Select ( r = > r . Value ) . Where ( r = > r ! = null ) . OrderBy ( r = > r . Order ) ;
foreach ( var redemption in ordered )
2024-07-06 23:42:33 -04:00
{
2025-01-06 09:36:54 -05:00
if ( redemption . ActionName = = null )
2024-07-06 23:42:33 -04:00
{
2025-01-06 09:36:54 -05:00
_logger . Warning ( "Null value found for the action name of a redemption." ) ;
continue ;
}
try
{
if ( _actions . ContainsKey ( redemption . ActionName ) )
{
_logger . Debug ( $"Fetched a redeemable action [redemption id: {redemption.Id}][redemption action: {redemption.ActionName}][order: {redemption.Order}]" ) ;
Add ( redemption . TwitchRedemptionId , redemption . Id ) ;
}
else
_logger . Warning ( $"Could not find redeemable action [redemption id: {redemption.Id}][redemption action: {redemption.ActionName}][order: {redemption.Order}]" ) ;
}
catch ( Exception e )
{
_logger . Error ( e , $"Failed to add a redemption [redemption id: {redemption.Id}][redemption action: {redemption.ActionName}][order: {redemption.Order}]" ) ;
2024-07-06 23:42:33 -04:00
}
}
2025-01-06 09:36:54 -05:00
}
_logger . Debug ( "All redemptions added. Redemption Manager is ready." ) ;
}
public bool RemoveAction ( string actionName )
{
return _actions . Remove ( actionName ) ;
}
public bool RemoveRedemption ( string redemptionId )
{
lock ( _lock )
{
if ( ! _redemptions . TryGetValue ( redemptionId , out var redemption ) )
{
return false ;
}
_redemptions . Remove ( redemptionId ) ;
if ( _redeems . TryGetValue ( redemption . TwitchRedemptionId , out var redeem ) )
2024-07-06 23:42:33 -04:00
{
2025-01-06 09:36:54 -05:00
redeem . Remove ( redemptionId ) ;
if ( ! redeem . Any ( ) )
_redeems . Remove ( redemption . TwitchRedemptionId ) ;
return true ;
2024-07-06 23:42:33 -04:00
}
}
2025-01-06 09:36:54 -05:00
return false ;
2024-06-24 18:11:36 -04:00
}
2024-07-06 23:42:33 -04:00
private string ReplaceContentText ( string content , string username )
{
return content . Replace ( "%USER%" , username )
. Replace ( "\\n" , "\n" ) ;
2024-06-24 18:11:36 -04:00
}
2025-01-06 09:36:54 -05:00
public bool Update ( Redemption redemption )
{
lock ( _lock )
{
if ( _redemptions . TryGetValue ( redemption . Id , out var r ) )
{
if ( r . Order ! = redemption . Order & & _redeems . TryGetValue ( redemption . TwitchRedemptionId , out var redeems ) & & redeems . Count > 1 )
{
var redemptions = redeems . Select ( r = > _redemptions . TryGetValue ( r , out var rr ) ? rr : null ) . ToArray ( ) ;
int index = redeems . IndexOf ( redemption . Id ) , i ;
if ( r . Order < redemption . Order )
{
for ( i = index ; i > = 1 ; i - - )
{
if ( redemptions [ i - 1 ] = = null | | redemption . Order < redemptions [ i - 1 ] ! . Order )
redeems [ i ] = redeems [ i - 1 ] ;
else
break ;
}
}
else
{
for ( i = index ; i < redeems . Count - 1 ; i + + )
{
if ( redemptions [ i + 1 ] = = null | | redemption . Order > redemptions [ i + 1 ] ! . Order )
redeems [ i ] = redeems [ i + 1 ] ;
else
break ;
}
}
redeems [ i ] = redemption . Id ;
}
else
{
r . ActionName = redemption . ActionName ;
r . State = redemption . State ;
r . TwitchRedemptionId = redemption . TwitchRedemptionId ;
r . Order = redemption . Order ;
}
_logger . Debug ( $"Updated redemption in redemption manager [redemption id: {redemption.Id}][redemption action: {redemption.ActionName}]" ) ;
return true ;
}
}
_logger . Warning ( $"Cannot find redemption by name [redemption id: {redemption.Id}][redemption action: {redemption.ActionName}]" ) ;
return false ;
}
public bool Update ( RedeemableAction action )
{
if ( _actions . TryGetValue ( action . Name , out var a ) )
{
a . Type = action . Type ;
a . Data = action . Data ;
_logger . Debug ( $"Updated redeemable action in redemption manager [action name: {action.Name}]" ) ;
return true ;
}
_logger . Warning ( $"Cannot find redeemable action by name [action name: {action.Name}]" ) ;
return false ;
}
2024-06-24 18:11:36 -04:00
}
}