Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.sh text eol=lf
external/linux/** text eol=lf
17 changes: 15 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
dotnet-version: '9.0.x'

- name: Cache NuGet packages
uses: actions/cache@v5
uses: actions/cache@v6
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }}
Expand Down Expand Up @@ -97,7 +97,7 @@ jobs:
dotnet-version: '9.0.x'

- name: Cache NuGet packages
uses: actions/cache@v5
uses: actions/cache@v6
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }}
Expand Down Expand Up @@ -250,6 +250,17 @@ jobs:
exit 1
fi
cp external/streamerbot/*.sb ./ || true

- name: Package Stream Deck plugin
run: |
sdplugin=external/streamdeck/com.wolfwithsword.subathonmanager.sdPlugin
mkdir -p $sdplugin/images
for spec in pluginIcon:28 categoryIcon:28 actionIcon:20 keyIcon:72; do
name=${spec%%:*}; size=${spec##*:}
convert assets/icon.png -resize ${size}x${size} $sdplugin/images/${name}.png
convert assets/icon.png -resize $((size*2))x$((size*2)) $sdplugin/images/${name}@2x.png
done
(cd external/streamdeck && zip -r ../../SubathonManager_StreamDeck.streamDeckPlugin com.wolfwithsword.subathonmanager.sdPlugin)


- name: Create GitHub Release
Expand All @@ -260,6 +271,7 @@ jobs:
files: |
${{ needs.build.outputs.filename }}
*.sb
*.streamDeckPlugin
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down Expand Up @@ -290,6 +302,7 @@ jobs:
files: |
${{ needs.build.outputs.filename }}
*.sb
*.streamDeckPlugin
token: ${{ secrets.GITHUB_TOKEN }}

notify:
Expand Down
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,8 @@ bin
obj

TestResults/
coverage-report/
coverage-report/

# Stream Deck plugin packaging stuff
*.streamDeckPlugin
external/streamdeck/**/images/
1 change: 1 addition & 0 deletions SubathonManager.Core/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ private void CreateDefault()

foreach (Core.Enums.SubathonEventType type in Enum.GetValues(typeof(Core.Enums.SubathonEventType)))
{
if (type.GetLegacyGoAffProSiteId() > 0) continue; // retired per-store values
Data["Discord"][$"Events.Log.{type}"] = $"{false}";
}
Data["Discord"]["Events.Log.Simulated"] = $"{false}";
Expand Down
16 changes: 7 additions & 9 deletions SubathonManager.Core/Enums/EnumExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Reflection;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;

// ReSharper disable NullableWarningSuppressionIsUsed

namespace SubathonManager.Core.Enums;
Expand Down Expand Up @@ -65,6 +67,8 @@ public class EventSourceMetaAttribute : EnumMetaAttribute
public bool Visible { get; init; } = true;
public SubathonEventSource TrueSource { get; init; } = SubathonEventSource.Unknown;
public int SourceOrder { get; init; } = 99999;

public bool IsExternalSource { get; init; } = false;
}

public class EventTypeMetaAttribute : EnumMetaAttribute
Expand Down Expand Up @@ -92,18 +96,12 @@ public class EventTypeMetaAttribute : EnumMetaAttribute
public SubathonEventSource Source { get; set; } = SubathonEventSource.Unknown;
}

[ExcludeFromCodeCoverage]
public class GoAffProTypeMetaAttribute : EventTypeMetaAttribute
{
public override string? Description => Label;
public GoAffProSource StoreSource { get; init; } = GoAffProSource.Unknown;
}


public class GoAffProSourceMetaAttribute : EnumMetaAttribute
{
public SubathonEventType OrderEvent { get; init; } = SubathonEventType.Unknown;

public int SiteId { get; init; } = -1;
// maintaining for legacy data
public int LegacySiteId { get; init; } = -1;
}

public class CommandMetaAttribute : EnumMetaAttribute
Expand Down
66 changes: 0 additions & 66 deletions SubathonManager.Core/Enums/GoAffProSource.cs

This file was deleted.

9 changes: 9 additions & 0 deletions SubathonManager.Core/Enums/MakeShipProductType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace SubathonManager.Core.Enums;

public enum MakeShipProductType
{
Unknown,
Petition,
Campaign,
Invalid // bad url usually
}
3 changes: 2 additions & 1 deletion SubathonManager.Core/Enums/SubathonCommandType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public enum SubathonCommandType
AddSpins,
[CommandMeta(Description="Subtract Wheel Spins", RequiresParameter = true)]
SubtractSpins,

[CommandMeta(Description="Spin the Wheel", IsControlType = true)]
SpinWheel,
}

[ExcludeFromCodeCoverage]
Expand Down
23 changes: 18 additions & 5 deletions SubathonManager.Core/Enums/SubathonEventSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@ public enum SubathonEventSource
Unknown, // default
[EventSourceMeta(Description = "StreamLabs", SourceGroup = SubathonSourceGroup.StreamExtension, SourceOrder=22, Order=21)]
StreamLabs,
[EventSourceMeta(Description = "Generic External Services", SourceGroup = SubathonSourceGroup.ExternalService, SourceOrder=1000, Order=99)]
[EventSourceMeta(Description = "Generic External Services", SourceGroup = SubathonSourceGroup.ExternalService, SourceOrder=1000, Order=99, IsExternalSource = true)]
External,
[EventSourceMeta(Description = "Blerp", SourceGroup = SubathonSourceGroup.StreamExtension, SourceOrder=81, Order=30)]
[EventSourceMeta(Description = "Blerp", SourceGroup = SubathonSourceGroup.StreamExtension, SourceOrder=81, Order=30, IsExternalSource = true)]
Blerp,
[EventSourceMeta(Description = "Picarto", SourceGroup = SubathonSourceGroup.Stream, SourceOrder=3, Order=12)]
Picarto,
[EventSourceMeta(Description = "GoAffPro Affiliate Stores", SourceGroup = SubathonSourceGroup.ExternalService, SourceOrder=61, Order=50, Visible = true)]
GoAffPro,
[EventSourceMeta(Description = "Ko-Fi (Tunnel)", SourceGroup = SubathonSourceGroup.ExternalService, SourceOrder=42, Visible=false, TrueSource=KoFi, Order=41)]
KoFiTunnel,
[EventSourceMeta(Description = "Dev Tunnels", SourceGroup = SubathonSourceGroup.ExternalService, SourceOrder=70, Visible=false, Order=120)]
[EventSourceMeta(Description = "Dev Tunnels", SourceGroup = SubathonSourceGroup.ExternalSoftware, SourceOrder=904, Visible=false, Order=903)]
DevTunnels,
[EventSourceMeta(Description="FourthWall", SourceGroup = SubathonSourceGroup.ExternalService, SourceOrder=62, Order=51)]
FourthWall,
[EventSourceMeta(Description="OBS Websocket", SourceGroup = SubathonSourceGroup.Unknown, SourceOrder=999, Order=999, Visible = false)]
[EventSourceMeta(Description="OBS", SourceGroup = SubathonSourceGroup.ExternalSoftware, SourceOrder=901, Order=900, Visible = false)]
OBS,
[EventSourceMeta(Description="Throne", SourceGroup = SubathonSourceGroup.ExternalService, SourceOrder=63, Order=52)]
Throne,
Expand All @@ -45,7 +45,17 @@ public enum SubathonEventSource
[EventSourceMeta(Description="Wheel Spin", Visible = false, Order = 990, SourceGroup = SubathonSourceGroup.WheelSpin)]
WheelSpin,
[EventSourceMeta(Description="Tangia", SourceGroup = SubathonSourceGroup.StreamExtension, SourceOrder=82, Order=31)]
Tangia
Tangia,
[EventSourceMeta(Description="Stream Deck", SourceGroup = SubathonSourceGroup.ExternalSoftware, SourceOrder=903, Order=902, Visible = false, IsExternalSource = true)]
StreamDeck,
[EventSourceMeta(Description="StreamerBot", SourceGroup = SubathonSourceGroup.ExternalSoftware, SourceOrder=902, Order=901, Visible = false, IsExternalSource = true)]
StreamerBot,
[EventSourceMeta(Description="Pally.GG", SourceGroup = SubathonSourceGroup.ExternalService, SourceOrder=64, Order=53)]
PallyGG,
[EventSourceMeta(Description="TreatStream", SourceGroup = SubathonSourceGroup.StreamExtension, SourceOrder=24, Order=23)]
TreatStream,
[EventSourceMeta(Description="MakeShip", SourceGroup = SubathonSourceGroup.ExternalService, SourceOrder=65, Order=54)]
MakeShip,
}

[ExcludeFromCodeCoverage]
Expand All @@ -59,6 +69,9 @@ public static class SubathonEventSourceHelper
var meta = EnumMetaCache.Get<EventSourceMetaAttribute>(value);
return meta;
}

public static bool IsExternalSource(this SubathonEventSource? source) => source.Meta()?.IsExternalSource ?? false;
public static bool IsExternalSource(this SubathonEventSource source) => IsExternalSource((SubathonEventSource?)source);

public static SubathonSourceGroup GetGroup(this SubathonEventSource source) =>
((SubathonEventSource?)source).Meta()?.SourceGroup ?? SubathonSourceGroup.Unknown;
Expand Down
75 changes: 52 additions & 23 deletions SubathonManager.Core/Enums/SubathonEventType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,21 @@ public enum SubathonEventType
[EventTypeMeta(Label = "Kudos Tip", Source = SubathonEventSource.Picarto, IsToken = true, Order = 3)]
PicartoTip,

[Obsolete]
[GoAffProTypeMeta(Label = "GamerSupps Order", Source = SubathonEventSource.GoAffPro, IsOrder = true, Order = 1,
StoreSource = GoAffProSource.GamerSupps, Enabled = true)]
LegacySiteId = 165328, Enabled = false)]
GamerSuppsOrder,

[Obsolete]
[GoAffProTypeMeta(Label = "UwUMarket Order", Source = SubathonEventSource.GoAffPro, IsOrder = true, Order = 2,
StoreSource = GoAffProSource.UwUMarket, Enabled = true)]
LegacySiteId = 132230, Enabled = false)]
UwUMarketOrder,

[GoAffProTypeMeta(Label = "Orchid Eight Order", Source = SubathonEventSource.GoAffPro, IsOrder = true, Order = 3,
StoreSource = GoAffProSource.OrchidEight, Enabled = true)]
LegacySiteId = 7142837, Enabled = false)]
OrchidEightOrder,

[Obsolete]
[GoAffProTypeMeta(Label = "KatDragonz Order", Source = SubathonEventSource.GoAffPro, IsOrder = true, Order = 4,
StoreSource = GoAffProSource.KatDragonz, Enabled = true)]
LegacySiteId = 7160049, Enabled = false)]
KatDragonzOrder,

[EventTypeMeta(Label = "Redirect/Raid", Source = SubathonEventSource.YouTube, IsRaid = true, Order = 5)]
Expand Down Expand Up @@ -133,13 +134,13 @@ public enum SubathonEventType
[EventTypeMeta(Label = "Gift Order", Source = SubathonEventSource.FourthWall, IsOrder = true, IsExternal = true,
Order = 4)]
FourthWallGiftOrder,

[Obsolete]
[GoAffProTypeMeta(Label = "Cheeky Soap Order", Source = SubathonEventSource.GoAffPro, IsOrder = true, Order = 5,
StoreSource = GoAffProSource.CheekySoap, Enabled = true)]
LegacySiteId = 7138531, Enabled = false)]
CheekySoapOrder,

[Obsolete]
[GoAffProTypeMeta(Label = "Advanced GG Order", Source = SubathonEventSource.GoAffPro, IsOrder = true, Order = 6,
StoreSource = GoAffProSource.AdvancedGG, Enabled = true)]
LegacySiteId = 105752, Enabled = false)]
AdvancedGGOrder,

[EventTypeMeta(Label = "Gift Purchase", Source = SubathonEventSource.Throne, Order = 1,
Expand All @@ -156,29 +157,47 @@ public enum SubathonEventType
IsGenericEvent = true)]
// will come in if contribution fully funds, so purely an alert, not event to add. So we do not allow configuration of it
ThroneCrowdGiftComplete, // only config in settings is whether or not to display it
[Obsolete]
[GoAffProTypeMeta(Label = "Rogue Energy Order", Source = SubathonEventSource.GoAffPro, IsOrder = true, Order = 7,
StoreSource = GoAffProSource.RogueEnergy, Enabled = true)]
LegacySiteId = 7014645, Enabled = false)]
RogueEnergyOrder,

[Obsolete]
[GoAffProTypeMeta(Label = "Saucy Biz Order", Source = SubathonEventSource.GoAffPro, IsOrder = true, Order = 8,
StoreSource = GoAffProSource.SaucyBiz, Enabled = true)]
LegacySiteId = 7118656, Enabled = false)]
SaucyBizOrder,
// PLACEHOLDER FOR FUTURE
[GoAffProTypeMeta(Label="GoAffPro Order", Source=SubathonEventSource.GoAffPro, IsOrder=true, Order=1, Enabled=false)]
GoAffProOrder,

// dynamic GoAffPro order type, meta is site id
[GoAffProTypeMeta(Label="GoAffPro Order", Source=SubathonEventSource.GoAffPro, IsOrder=true, Order=1, Enabled=true)]
GoAffProOrder,
[Obsolete]
[GoAffProTypeMeta(Label = "GFuel Order", Source = SubathonEventSource.GoAffPro, IsOrder = true, Order = 9,
StoreSource = GoAffProSource.GFuel, Enabled = true)]
LegacySiteId = 48808, Enabled = false)]
GFuelOrder,
[Obsolete]
[GoAffProTypeMeta(Label = "Natura Pine Order", Source = SubathonEventSource.GoAffPro, IsOrder = true, Order = 10,
StoreSource = GoAffProSource.NaturaPine, Enabled = true)]
LegacySiteId = 7132796, Enabled = false)]
NaturaPineOrder,

[EventTypeMeta(Label = "Donation", Source = SubathonEventSource.TipeeeStream, IsCurrencyDonation = true, Order = 1)]
TipeeeStreamDonation,
[EventTypeMeta(Label = "Tokens", Source = SubathonEventSource.Tangia, IsToken = true, Order = 1)]
TangiaTokens, // no way to distinguish twitch bits or tangia coins

[EventTypeMeta(Label = "Donation", Source = SubathonEventSource.PallyGG, IsCurrencyDonation = true, IsExternal = true,
Order = 1)]
// Pally.gg is USD only :/
PallyGGDonation,

[EventTypeMeta(Label = "Order", Source = SubathonEventSource.TreatStream, IsOrder = true, Order = 1)]
TreatStreamOrder,

// items only
[EventTypeMeta(Label = "Pledge", Source = SubathonEventSource.MakeShip, IsOrder = true, Order = 1)]
MakeShipPledge,
// items only
[EventTypeMeta(Label = "Campaign Sale", Source = SubathonEventSource.MakeShip, IsOrder = true, Order = 2)]
MakeShipOrder,

// any new must be added after the last
}

Expand Down Expand Up @@ -257,13 +276,23 @@ public static SubathonEventSubType GetSubType(this SubathonEventType? eventType)
return SubathonEventSubType.Unknown;
}

public static string? GetTypeTrueSource(this SubathonEventType eventType) => GetTypeTrueSource((SubathonEventType?)eventType);
public static string? GetTypeTrueSource(this SubathonEventType? eventType)
public static string? GetTypeTrueSource(this SubathonEventType eventType, string? meta = null) => GetTypeTrueSource((SubathonEventType?)eventType, meta);

public static string? GetTypeTrueSource(this SubathonEventType? eventType, string? meta = null)
{
if (eventType is null or SubathonEventType.Command) return "Manual";
if (eventType.GetSource() == SubathonEventSource.GoAffPro) return eventType.GoAffProMeta()?.StoreSource.ToString();
if (eventType.GetSource() == SubathonEventSource.GoAffPro)
{
var siteId = eventType == SubathonEventType.GoAffProOrder && meta != null && int.TryParse(meta, out var parsed)
? parsed
: eventType.GoAffProMeta()?.LegacySiteId ?? -1;
return GoAffProStoreRegistry.TryGetBySiteId(siteId, out var store)
? store.InternalName
: nameof(SubathonEventSource.GoAffPro);
}
return eventType.GetSource().ToString();
}


public static int GetLegacyGoAffProSiteId(this SubathonEventType eventType) =>
((SubathonEventType?)eventType).GoAffProMeta()?.LegacySiteId ?? -1;
}
Loading
Loading