├── .editorconfig
├── .gitattributes
├── .github
├── FUNDING.yml
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── setup_help.md
├── .gitignore
├── .gitmodules
├── GitVersion.yml
├── InstallOpus.sh
├── LICENSE
├── LICENSE_COMPLETE
├── README.md
├── TS3ABotUnitTests
├── BotCommandTests.cs
├── ColorGeneratorTests.cs
├── HistoryTests.cs
├── M3uParserTests.cs
├── ResourceFactoriesTests.cs
├── RingQueueTest.cs
├── ShuffleTests.cs
├── TS3ABotUnitTests.csproj
├── TS3MessageParserTests.cs
├── TextSplitterTests.cs
└── UtilsTests.cs
├── TS3AudioBot.sln
├── TS3AudioBot
├── Algorithm
│ ├── IFilterAlgorithm.cs
│ ├── LruCache.cs
│ └── TimedCache.cs
├── Audio
│ ├── AudioValues.cs
│ ├── CustomTargetPipe.cs
│ ├── FfmpegProducer.cs
│ ├── IPlayerSource.cs
│ ├── IVoiceTarget.cs
│ ├── PlayInfo.cs
│ ├── PlayInfoEventArgs.cs
│ ├── PlayManager.cs
│ ├── Player.cs
│ ├── SongEndEventArgs.cs
│ ├── SongInfoChanged.cs
│ ├── StallCheckPipe.cs
│ └── StreamAudioPlayerSource.cs
├── Bot.cs
├── BotManager.cs
├── CallerInfo.cs
├── ClientCall.cs
├── CommandSystem
│ ├── Ast
│ │ ├── AstCommand.cs
│ │ ├── AstError.cs
│ │ ├── AstNode.cs
│ │ ├── AstType.cs
│ │ ├── AstValue.cs
│ │ └── StringType.cs
│ ├── BotCommand.cs
│ ├── CommandAttribute.cs
│ ├── CommandException.cs
│ ├── CommandManager.cs
│ ├── CommandParser.cs
│ ├── CommandResults
│ │ ├── IAudioResourceResult.cs
│ │ ├── IWrappedResult.cs
│ │ ├── PickObjectCommand.cs
│ │ └── TailString.cs
│ ├── CommandSystemExtensions.cs
│ ├── CommandSystemTypes.cs
│ ├── Commands
│ │ ├── AliasCommand.cs
│ │ ├── AppliedCommand.cs
│ │ ├── CommandGroup.cs
│ │ ├── FunctionCommand.cs
│ │ ├── ICommand.cs
│ │ ├── LazyCommand.cs
│ │ ├── OverloadedFunctionCommand.cs
│ │ ├── ResultCommand.cs
│ │ └── RootCommand.cs
│ ├── ExecutionInformation.cs
│ ├── ICommandBag.cs
│ ├── StaticList.cs
│ └── Text
│ │ ├── AppliedTextMod.cs
│ │ ├── Color.cs
│ │ ├── LongTextBehaviour.cs
│ │ ├── LongTextTransform.cs
│ │ ├── TextMod.cs
│ │ ├── TextModBuilder.cs
│ │ ├── TextModFlag.cs
│ │ └── TextModHelper.cs
├── Config
│ ├── Config.cs
│ ├── ConfigArray.cs
│ ├── ConfigDynamicTable.cs
│ ├── ConfigEnumerable.cs
│ ├── ConfigHelper.cs
│ ├── ConfigPart.cs
│ ├── ConfigStructs.cs
│ ├── ConfigTable.cs
│ ├── ConfigUpgrade2.cs
│ └── ConfigValue.cs
├── Core.cs
├── DbStore.cs
├── Dependency
│ ├── BasicInjector.cs
│ ├── ChainedInjector.cs
│ ├── DependencyBuilder.cs
│ ├── IInjector.cs
│ ├── InjectorExtensions.cs
│ ├── Module.cs
│ └── NullInjector.cs
├── Environment
│ ├── Stats.cs
│ ├── SystemData.cs
│ └── SystemMonitor.cs
├── Error.cs
├── Helper
│ ├── AttributeStrings.cs
│ ├── Const.cs
│ ├── Diagnose
│ │ ├── SelfDiagnoseLevel.cs
│ │ └── SelfDiagnoseMessage.cs
│ ├── IJsonConfig.cs
│ ├── ImageUtil.cs
│ ├── Interactive.cs
│ ├── LimitStream.cs
│ ├── TextUtil.cs
│ ├── TomlTools.cs
│ ├── Util.cs
│ └── WebWrapper.cs
├── History
│ ├── AudioLogEntry.cs
│ ├── HistoryManager.cs
│ ├── HistorySaveData.cs
│ ├── IHistoryFormatter.cs
│ ├── SearchQuery.cs
│ └── SmartHistoryFormatter.cs
├── InvokerData.cs
├── Limits.cs
├── Localization
│ ├── DynamicResourceManager.cs
│ ├── LocalStr.cs
│ ├── LocalizationManager.cs
│ ├── strings.Designer.cs
│ └── strings.resx
├── MainCommands.cs
├── Media
│ ├── SleepingKitty.png
│ ├── SleepingKitty.svg
│ └── favicon.ico
├── Playlists
│ ├── LoopMode.cs
│ ├── Parser
│ │ └── JspfContent.cs
│ ├── Playlist.cs
│ ├── PlaylistApiExtensions.cs
│ ├── PlaylistIO.cs
│ ├── PlaylistItem.cs
│ ├── PlaylistManager.cs
│ └── Shuffle
│ │ ├── IShuffleAlgorithm.cs
│ │ ├── LinearFeedbackShiftRegister.cs
│ │ ├── ListedShuffle.cs
│ │ └── NormalOrder.cs
├── Plugins
│ ├── ITabPlugin.cs
│ ├── Plugin.cs
│ ├── PluginCommandBag.cs
│ ├── PluginExtensions.cs
│ ├── PluginManager.cs
│ ├── PluginObjects.cs
│ ├── PluginResponse.cs
│ └── PluginStatus.cs
├── Properties.cs
├── ResourceFactories
│ ├── AudioResource.cs
│ ├── AudioTags
│ │ ├── AudioTagReader.cs
│ │ ├── BinaryReaderBigEndianExtensions.cs
│ │ └── M3uReader.cs
│ ├── BandcampResolver.cs
│ ├── IPlaylistResolver.cs
│ ├── IResolver.cs
│ ├── IResourceResolver.cs
│ ├── ISearchResolver.cs
│ ├── IThumbnailResolver.cs
│ ├── MatchCertainty.cs
│ ├── MediaResolver.cs
│ ├── PlayResource.cs
│ ├── ResolveContext.cs
│ ├── ResourceResolver.cs
│ ├── SongInfo.cs
│ ├── SoundcloudResolver.cs
│ ├── TwitchResolver.cs
│ ├── Youtube
│ │ ├── Json.cs
│ │ ├── LoaderPriority.cs
│ │ ├── VideoCodec.cs
│ │ ├── VideoData.cs
│ │ └── YoutubeResolver.cs
│ └── YoutubeDlHelper.cs
├── Resources
│ ├── DefaultRights.toml
│ └── NLog.config
├── Rights
│ ├── CreateFileSettings.cs
│ ├── ExecuteContext.cs
│ ├── Matchers
│ │ ├── MatchApiCallerIp.cs
│ │ ├── MatchBot.cs
│ │ ├── MatchChannelGroupId.cs
│ │ ├── MatchClientGroupId.cs
│ │ ├── MatchClientUid.cs
│ │ ├── MatchHost.cs
│ │ ├── MatchIsApi.cs
│ │ ├── MatchPermission.cs
│ │ ├── MatchToken.cs
│ │ ├── MatchVisibility.cs
│ │ ├── Matcher.cs
│ │ └── PermCompare.cs
│ ├── ParseContext.cs
│ ├── RightsDecl.cs
│ ├── RightsGroup.cs
│ ├── RightsManager.cs
│ └── RightsRule.cs
├── Sessions
│ ├── AnonymousSession.cs
│ ├── ApiToken.cs
│ ├── SessionManager.cs
│ ├── TokenManager.cs
│ └── UserSession.cs
├── Setup.cs
├── TS3AudioBot.csproj
├── Ts3Client.cs
├── Upgrader.cs
├── Web
│ ├── Api
│ │ ├── ApiCall.cs
│ │ ├── DataStream.cs
│ │ ├── JsonArray.cs
│ │ ├── JsonEmpty.cs
│ │ ├── JsonError.cs
│ │ ├── JsonObject.cs
│ │ ├── JsonValue.cs
│ │ ├── OpenApiGenerator.cs
│ │ ├── TimeSpanConverter.cs
│ │ └── WebApi.cs
│ ├── Model
│ │ ├── CurrentSongInfo.cs
│ │ ├── PlaylistInfo.cs
│ │ ├── PlaylistItemGetData.cs
│ │ └── QueueInfo.cs
│ └── WebServer.cs
├── build.csx
└── lib
│ ├── x64
│ └── libopus.dll
│ └── x86
│ └── libopus.dll
├── TSLib
├── Audio
│ ├── AudioInterfaces.cs
│ ├── AudioMeta.cs
│ ├── AudioPacketReader.cs
│ ├── AudioPipeExtensions.cs
│ ├── AudioTools.cs
│ ├── CheckActivePipe.cs
│ ├── ClientMixdown.cs
│ ├── DecoderPipe.cs
│ ├── EncoderPipe.cs
│ ├── Opus
│ │ ├── LICENSE
│ │ ├── NativeMethods.cs
│ │ ├── OPUS_LICENSE
│ │ ├── OpusDecoder.cs
│ │ ├── OpusEncoder.cs
│ │ └── README
│ ├── PassiveMergePipe.cs
│ ├── PassiveSplitterPipe.cs
│ ├── PreciseAudioTimer.cs
│ ├── PreciseTimedPipe.cs
│ ├── StaticMetaPipe.cs
│ ├── StreamAudioProducer.cs
│ └── VolumePipe.cs
├── Commands
│ ├── CommandMultiParameter.cs
│ ├── CommandOption.cs
│ ├── CommandParameter.cs
│ ├── ICommandPart.cs
│ ├── TsCommand.cs
│ ├── TsCommand.gen.cs
│ ├── TsCommand.gen.tt
│ ├── TsConst.cs
│ └── TsString.cs
├── ConnectionData.cs
├── DisconnectEventArgs.cs
├── EventDispatcher.cs
├── Full
│ ├── Book
│ │ ├── Book.cs
│ │ └── SpecialTypes.cs
│ ├── GenerationWindow.cs
│ ├── IdentityData.cs
│ ├── License.cs
│ ├── NetworkStats.cs
│ ├── Packet.cs
│ ├── PacketHandler.cs
│ ├── PacketType.cs
│ ├── QuickerLz.cs
│ ├── RingQueue.cs
│ ├── TsCrypt.cs
│ ├── TsFullClient.cs
│ ├── TsFullClient.gen.cs
│ └── TsFullClient.gen.tt
├── Generated
│ ├── Book.cs
│ ├── Book.tt
│ ├── BookParser.ttinclude
│ ├── ErrorParser.ttinclude
│ ├── M2B.cs
│ ├── M2B.tt
│ ├── M2BParser.ttinclude
│ ├── MessageParser.ttinclude
│ ├── Messages.cs
│ ├── Messages.tt
│ ├── NotificationUtil.ttinclude
│ ├── TsErrorCode.cs
│ ├── TsErrorCode.tt
│ ├── TsPermission.cs
│ ├── TsPermission.tt
│ ├── TsVersion.gen.cs
│ ├── TsVersion.gen.tt
│ └── Util.ttinclude
├── Helper
│ ├── AsyncEventHandler.cs
│ ├── CommandErrorExtensions.cs
│ ├── DebugUtil.cs
│ ├── LogId.cs
│ ├── MissingEnumCaseException.cs
│ ├── NativeLibraryLoader.cs
│ ├── R.cs
│ ├── SpanExtensions.cs
│ ├── SpanSplitter.cs
│ └── Tools.cs
├── LazyNotification.cs
├── MessageProcessor.cs
├── Messages
│ ├── BaseTypes.cs
│ ├── Deserializer.cs
│ ├── MessageAdditions.cs
│ ├── PermissionTransform.cs
│ └── ResponseDictionary.cs
├── Properties.cs
├── Query
│ ├── TsQueryClient.cs
│ ├── TsQueryClient.gen.cs
│ └── TsQueryClient.gen.tt
├── ReSpeak.png
├── Scheduler
│ ├── DedicatedTaskScheduler.cs
│ ├── DispatcherHelper.cs
│ └── TickWorker.cs
├── TSLib.csproj
├── TsBaseFunctions.FileTransfer.cs
├── TsBaseFunctions.cs
├── TsBaseFunctions.gen.cs
├── TsBaseFunctions.gen.tt
├── TsDnsResolver.cs
├── TsEnums.cs
├── TsPermissionHelper.cs
├── TsVersion.cs
├── Types.cs
├── Types.gen.cs
├── Types.gen.tt
├── WaitBlock.cs
└── dnc2_compat
│ ├── Extensions.cs
│ ├── Range.cs
│ └── info.txt
├── Tools
├── pack_linux.csx
├── ts3notify.ps1
└── ts3notify.sh
├── WebInterface
├── package-lock.json
├── package.json
├── src
│ ├── html
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── openapi
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ ├── index.html
│ │ │ ├── oauth2-redirect.html
│ │ │ ├── swagger-ui-bundle.js
│ │ │ ├── swagger-ui-bundle.js.map
│ │ │ ├── swagger-ui-standalone-preset.js
│ │ │ ├── swagger-ui-standalone-preset.js.map
│ │ │ ├── swagger-ui.css
│ │ │ ├── swagger-ui.css.map
│ │ │ ├── swagger-ui.js
│ │ │ └── swagger-ui.js.map
│ ├── less
│ │ └── styles_formdata.less
│ └── ts
│ │ ├── Api.ts
│ │ ├── ApiAuth.ts
│ │ ├── ApiObjects.ts
│ │ ├── App.vue
│ │ ├── Components
│ │ ├── BotNavbarItem.vue
│ │ ├── EditableText.vue
│ │ ├── Hovercon.vue
│ │ ├── Navbar.vue
│ │ ├── PlayControls.vue
│ │ ├── PlaybackInfo.vue
│ │ ├── PlaylistEditor.vue
│ │ ├── ServerTree.vue
│ │ ├── ServerTreeNode.vue
│ │ ├── ServerTreeUser.vue
│ │ ├── SettingsField.vue
│ │ ├── SettingsGroup.vue
│ │ ├── SettingsPassword.vue
│ │ └── VCanvas.vue
│ │ ├── Graph.ts
│ │ ├── Main.ts
│ │ ├── Modals
│ │ ├── CreateBotModal.vue
│ │ ├── CreatePlaylistModal.vue
│ │ ├── DeleteBotModal.vue
│ │ ├── DeletePlaylistModal.vue
│ │ ├── EnterPasswordModal.vue
│ │ ├── QuickConnectModal.vue
│ │ └── SiteSettingsModal.vue
│ │ ├── Model
│ │ ├── BotInfoSync.ts
│ │ ├── BotStatus.ts
│ │ ├── Languge.ts
│ │ ├── PlayState.ts
│ │ ├── RepeatKind.ts
│ │ ├── SettingsLevel.ts
│ │ ├── SpacerType.ts
│ │ └── TargetSendMode.ts
│ │ ├── Pages
│ │ ├── Bot.vue
│ │ ├── BotServer.vue
│ │ ├── BotSettings.vue
│ │ ├── Bots.vue
│ │ ├── Commands.vue
│ │ ├── Home.vue
│ │ ├── OpenApi.d.ts
│ │ ├── Overview.vue
│ │ └── Playlists.vue
│ │ ├── Timer.ts
│ │ ├── Util.ts
│ │ └── vue-shim.d.ts
├── tsconfig.json
├── tslint.json
├── webpack.config.js
├── webpack.development.config.js
└── webpack.production.config.js
└── appveyor.yml
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | patreon: Splamy
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is or what you expected to happen instead.
9 |
10 | **To Reproduce**
11 | Steps to reproduce the behavior (if possible)
12 |
13 | **Version**
14 | Which commit did you build or download? (mono TS3AudiBot.exe -V or !version in chat)
15 |
16 | **Platform**
17 | Which platform(-version) are you running on? (ubuntu 16.04, arch, windows,...)
18 | Which runtime(-version) are you using? (mono: mono -V, dotnet: dotnet --info)
19 |
20 | **Log**
21 | ```
22 | Paste the important log parts from the ts3audiobot.log into this code block here.
23 | Try not to paste too little.
24 | At best from the first to last interaction from you which reproduces this problem.
25 | ```
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/setup_help.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Setup help
3 | about: Problems setting up or running the bot
4 |
5 | ---
6 |
7 | **Describe the problem**
8 | A clear and concise description of what the problem is.
9 |
10 | **To Reproduce**
11 | Steps to reproduce the behavior
12 |
13 | **System Information**
14 | - **Platform**: (Ubuntu 16.04, Debian 8, Arch, etc)
15 |
16 | - **Mono version**: (`mono -V`)
17 |
18 | - **Which commit did you download**: (or on prebuilt: `mono TS3AudioBot.exe -V`)
19 |
20 | (If all fields in the TS3AudioBot log header are correctly filled you can
21 | alternatively just post the header here.)
22 |
23 | **Additional Logs, Exceptions, etc**
24 | When applicable try to add relevant log excerpts here.
25 |
26 | ```
27 | Put logs or code in triple backticks like here to properly format it.
28 | ```
29 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "TSLib/Declarations"]
2 | path = TSLib/Declarations
3 | url = https://github.com/ReSpeak/tsdeclarations
4 |
--------------------------------------------------------------------------------
/GitVersion.yml:
--------------------------------------------------------------------------------
1 | assembly-versioning-scheme: MajorMinorPatch
2 | mode: Mainline
3 | branches:
4 | master:
5 | tag: ''
6 | increment: Patch
7 | prevent-increment-of-merged-branch-version: true
8 | regex: ^master$
9 | is-mainline: true
10 | develop:
11 | mode: ContinuousDeployment
12 | tag: alpha
13 | increment: Minor
14 | prevent-increment-of-merged-branch-version: true
15 | regex: ^develop$
16 | ignore:
17 | sha: []
18 | merge-message-formats: {}
19 |
--------------------------------------------------------------------------------
/InstallOpus.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | baseDir=`pwd`
4 |
5 | OpusBaseName="opus-1.3.1"
6 | OpusFileName="$OpusBaseName.tar.gz"
7 |
8 | # Download the Opus library
9 | if [ ! -e "$OpusFileName" ]; then
10 | opusLink="http://downloads.xiph.org/releases/opus/$OpusFileName"
11 | echo "Downloading $opusLink"
12 | wget "$opusLink"
13 | else
14 | echo "Opus archive existing already"
15 | fi
16 |
17 | # Extract the archive
18 | tar -vxf "$OpusFileName"
19 |
20 | # Go into the extracted directory
21 | cd "$OpusBaseName"
22 |
23 | # Build the library
24 | ./configure && make && sudo make install
25 |
26 | # Move to global folder
27 | if [ ! -f /usr/lib/libopus.so ]; then
28 | sudo cp ".libs/libopus.so" "/usr/lib/"
29 | else
30 | echo "'/usr/lib/libopus.so' already exists, will not be overwritten"
31 | fi
32 |
33 | echo "Done"
34 |
--------------------------------------------------------------------------------
/TS3ABotUnitTests/ResourceFactoriesTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using TS3AudioBot.Config;
3 | using TS3AudioBot.ResourceFactories;
4 | using TS3AudioBot.ResourceFactories.Youtube;
5 |
6 | namespace TS3ABotUnitTests
7 | {
8 | [TestFixture]
9 | public class ResourceFactoriesTests
10 | {
11 | [Test]
12 | public void Factory_YoutubeFactoryTest()
13 | {
14 | var ctx = new ResolveContext(null, null);
15 | using IResourceResolver rfac = new YoutubeResolver(new ConfResolverYoutube());
16 | // matching links
17 | Assert.AreEqual(rfac.MatchResource(ctx, "https://www.youtube.com/watch?v=robqdGEhQWo"), MatchCertainty.Always);
18 | Assert.AreEqual(rfac.MatchResource(ctx, "https://youtu.be/robqdGEhQWo"), MatchCertainty.Always);
19 | Assert.AreEqual(rfac.MatchResource(ctx, "https://discarded-ideas.org/sites/discarded-ideas.org/files/music/darkforestkeep_symphonic.mp3"), MatchCertainty.Never);
20 | Assert.AreNotEqual(rfac.MatchResource(ctx, "http://splamy.de/youtube.com/youtu.be/fake.mp3"), MatchCertainty.Always);
21 |
22 | // restoring links
23 | Assert.AreEqual("https://youtu.be/robqdGEhQWo", rfac.RestoreLink(ctx, new AudioResource { ResourceId = "robqdGEhQWo" }));
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/TS3ABotUnitTests/ShuffleTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using System.Collections;
3 | using TS3AudioBot.Playlists.Shuffle;
4 |
5 | namespace TS3ABotUnitTests
6 | {
7 | [TestFixture]
8 | public class ShuffleTests
9 | {
10 | [Test]
11 | public void NormalOrderTest()
12 | {
13 | TestShuffleAlgorithmBiDir(new NormalOrder());
14 | }
15 |
16 | [Test]
17 | public void ListedShuffleTest()
18 | {
19 | TestShuffleAlgorithmBiDir(new ListedShuffle());
20 | }
21 |
22 | [Test]
23 | public void LinearFeedbackShiftRegisterTest()
24 | {
25 | TestShuffleAlgorithmBiDir(new LinearFeedbackShiftRegister());
26 | }
27 |
28 | private static void TestShuffleAlgorithmBiDir(IShuffleAlgorithm algo)
29 | {
30 | TestShuffleAlgorithm(algo, true);
31 | TestShuffleAlgorithm(algo, false);
32 | }
33 |
34 | private static void TestShuffleAlgorithm(IShuffleAlgorithm algo, bool forward)
35 | {
36 | for (int i = 1; i < 1000; i++)
37 | {
38 | var checkNumbers = new BitArray(i, false);
39 |
40 | algo.Length = i;
41 | algo.Seed = i;
42 |
43 | for (int j = 0; j < i; j++)
44 | {
45 | if (forward) algo.Next();
46 | else algo.Prev();
47 | int shufNum = algo.Index;
48 | if (checkNumbers.Get(shufNum))
49 | Assert.Fail("Duplicate number");
50 | checkNumbers.Set(shufNum, true);
51 | }
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/TS3ABotUnitTests/TS3ABotUnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Library
5 | netcoreapp3.1
6 |
7 | 8.0
8 | disable
9 | AnyCPU
10 | false
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/TS3ABotUnitTests/TextSplitterTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using System.Linq;
3 | using TS3AudioBot.CommandSystem.Text;
4 | using TSLib.Commands;
5 |
6 | namespace TS3ABotUnitTests
7 | {
8 | [TestFixture]
9 | public class TextSplitterTests
10 | {
11 | public const string Str1 = "Playlist: \"[B]asdf2[/B]\" with 110 songs.\n0: 【nami】 One of Repetition -「繰り返し一粒 」を歌ってみた\n1: God knows... ''The Melancholy of Haruhi Suzumiya'' 【涼宮ハルヒの憂鬱】Kadokawa公認MAD【ベース 演奏】\n2: Noucome op Full\n3: 麻枝 准×やなぎなぎ「無敵のSoldier」\n4: Nisemonogatari Opening 3 - Platinum Disco (Yuka Iguchi) HD\n5: SAO II OP Courage Full\n6: SAO II OP Ignite Full\n7: 「Secret base~君がくれたもの~」cover by【Mesxmokonax冥月x洛】\n8: [HQ] Yousei Teikoku - Kokou no Sousei\n9: Yousei Teikoku - Kikai Shoujo Gensou\n10: Yousei Teikoku- Tasogare no Gekka\n11: Yousei Teikoku - Wahrheit\n12: 【Karaoke】IA IA ★ Night of Desire【on vocal】 samfree\n13: [1080P Full風] Luka Luka★Night Fever ルカルカ★ナイトフィーバー 巡音ルカ Project DIVA English lyrics romaji subtitles\n14: Vocaloid - Nekomura Iroha - Cat Cat ☆Super Fever Night\n15: [Piko] \"Piko Piko ☆Legend Of The Night \" english subbed [english / romaji in the description]\n16: 【MMD】 Pomp And Circumstance 【Yukari & Lily】\n17: 【MMD】 Two Faced Lovers (Nikoman Ver.) 【CUL】\n18: 【CUL】「Aokigahara -青木ヶ原-」【Vocaloidカバー】\n19: 【MMD】 LUVORATORRRRRY! 【Kagamine Rin & GUMI】\n";
12 | public const int MaxSplit = 8192;
13 |
14 | [Test]
15 | public void Split()
16 | {
17 | for (int i = 4; i < MaxSplit; i++)
18 | {
19 | var parts = LongTextTransform.Split(Str1, LongTextBehaviour.SplitHard, maxMessageSize: i).ToArray();
20 | foreach (var part in parts)
21 | {
22 | Assert.LessOrEqual(TsString.TokenLength(part), i);
23 | }
24 | var joined = string.Concat(parts);
25 | Assert.AreEqual(Str1, joined);
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/TS3ABotUnitTests/UtilsTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using System.Text.RegularExpressions;
3 | using TS3AudioBot.Helper;
4 | using TSLib.Full;
5 |
6 | namespace TS3ABotUnitTests
7 | {
8 | [TestFixture]
9 | public class UtilsTests
10 | {
11 | [Test]
12 | public void UtilSeedTest()
13 | {
14 | var lowCaseRegex = new Regex("^[a-z]*$", Util.DefaultRegexConfig & ~RegexOptions.IgnoreCase);
15 | for (int i = 0; i < 100000; i++)
16 | {
17 | var str = Util.FromSeed(i);
18 | Assert.IsTrue(lowCaseRegex.IsMatch(str), "For seed: " + i);
19 | var roundtrip = Util.ToSeed(str);
20 | Assert.AreEqual(i, roundtrip);
21 | }
22 | }
23 |
24 | /* ======================= TSLib Tests ========================*/
25 |
26 | [Test]
27 | public void VersionSelfCheck()
28 | {
29 | TsCrypt.VersionSelfCheck();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/TS3AudioBot/Algorithm/TimedCache.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 | using System.Collections.Concurrent;
12 | using System.Diagnostics.CodeAnalysis;
13 | using System.Linq;
14 | using TSLib.Helper;
15 |
16 | namespace TS3AudioBot.Algorithm
17 | {
18 | public class TimedCache where TK : notnull
19 | {
20 | public TimeSpan Timeout { get; }
21 | private readonly ConcurrentDictionary cachedData;
22 |
23 | public TimedCache() : this(TimeSpan.FromSeconds(3)) { }
24 |
25 | public TimedCache(TimeSpan timeout)
26 | {
27 | Timeout = timeout;
28 | cachedData = new ConcurrentDictionary();
29 | }
30 |
31 | public bool TryGetValue(TK key, [MaybeNullWhen(false)] out TV value)
32 | {
33 | if (!cachedData.TryGetValue(key, out var data)
34 | || Tools.Now - Timeout > data.Timestamp)
35 | {
36 | CleanCache();
37 | value = default!;
38 | return false;
39 | }
40 | value = data.Data;
41 | return true;
42 | }
43 |
44 | public void Set(TK key, TV value)
45 | {
46 | cachedData[key] = new TimedData { Data = value, Timestamp = Tools.Now };
47 | }
48 |
49 | public void Clear()
50 | {
51 | cachedData.Clear();
52 | }
53 |
54 | private void CleanCache()
55 | {
56 | var now = Tools.Now - Timeout;
57 | foreach (var item in cachedData.Where(kvp => now > kvp.Value.Timestamp).ToList())
58 | {
59 | cachedData.TryRemove(item.Key, out _);
60 | }
61 | }
62 |
63 | private struct TimedData
64 | {
65 | public TV Data;
66 | public DateTime Timestamp;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/TS3AudioBot/Audio/AudioValues.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 | using TSLib.Helper;
12 |
13 | namespace TS3AudioBot.Audio
14 | {
15 | public static class AudioValues
16 | {
17 | public const float MinVolume = 0;
18 | public const float MaxVolume = 100;
19 |
20 | // Reference explanation for the logarithmic scale
21 | // https://www.dr-lex.be/info-stuff/volumecontrols.html#table1
22 | // Adjusted values for 40dB
23 |
24 | private const float fact_a = 1e-2f;
25 | private const float fact_b = 4.61512f;
26 |
27 | public static float HumanVolumeToFactor(float value)
28 | {
29 | if (value < MinVolume) return 0;
30 | if (value > MaxVolume) return 1;
31 |
32 | // Map input values from [MinVolume, MaxVolume] to [0, 1]
33 | value = (value - MinVolume) / (MaxVolume - MinVolume);
34 |
35 | // Scale the value logarithmically
36 | return Tools.Clamp((float)(fact_a * Math.Exp(fact_b * value)) - fact_a, 0, 1);
37 | }
38 |
39 | public static float FactorToHumanVolume(float value)
40 | {
41 | if (value < 0) return MinVolume;
42 | if (value > 1) return MaxVolume;
43 |
44 | // Undo logarithmical scale
45 | value = Tools.Clamp((float)(Math.Log((value + fact_a) / fact_a) / fact_b), 0, 1);
46 |
47 | // Map input values from [0, 1] to [MinVolume, MaxVolume]
48 | return (value * (MaxVolume - MinVolume)) + MinVolume;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/TS3AudioBot/Audio/IPlayerSource.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 | using System.Threading.Tasks;
12 | using TSLib.Audio;
13 |
14 | namespace TS3AudioBot.Audio
15 | {
16 | public interface IPlayerSource : IAudioPassiveProducer
17 | {
18 | event EventHandler OnSongEnd;
19 | event EventHandler OnSongUpdated;
20 |
21 | TimeSpan? Length { get; }
22 | TimeSpan? Position { get; }
23 |
24 | Task Seek(TimeSpan position);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/TS3AudioBot/Audio/PlayInfo.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 | using System.Diagnostics.CodeAnalysis;
12 | using TSLib;
13 |
14 | namespace TS3AudioBot.Audio
15 | {
16 | public sealed class PlayInfo
17 | {
18 | /// Defaults to: invoker.Uid - Can be set if the owner of a song differs from the invoker.
19 | public Uid? ResourceOwnerUid { get; set; }
20 | /// Starts the song at the specified time if set.
21 | public TimeSpan? StartOffset { get; set; }
22 |
23 | public PlayInfo(TimeSpan? startOffset = null)
24 | {
25 | StartOffset = startOffset;
26 | }
27 |
28 | public PlayInfo Merge(PlayInfo other) => Merge(this, other);
29 |
30 | [return: NotNullIfNotNull("self")]
31 | [return: NotNullIfNotNull("other")]
32 | public static PlayInfo? Merge(PlayInfo? self, PlayInfo? other)
33 | {
34 | if (other is null)
35 | return self;
36 | if (self is null)
37 | return other;
38 | self.ResourceOwnerUid ??= other.ResourceOwnerUid;
39 | self.StartOffset ??= other.StartOffset;
40 | return self;
41 | }
42 |
43 | public static PlayInfo MergeDefault(PlayInfo? self, PlayInfo? other)
44 | => Merge(self, other) ?? new PlayInfo();
45 | }
46 |
47 | public interface IMetaContainer
48 | {
49 | public PlayInfo? PlayInfo { get; set; }
50 | }
51 |
52 | public static class MetaContainerExtensions
53 | {
54 | public static T MergeMeta(this T container, PlayInfo? other) where T : IMetaContainer
55 | {
56 | container.PlayInfo = PlayInfo.Merge(container.PlayInfo, other);
57 | return container;
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/TS3AudioBot/Audio/PlayInfoEventArgs.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 | using TS3AudioBot.ResourceFactories;
12 |
13 | namespace TS3AudioBot.Audio
14 | {
15 | public sealed class PlayInfoEventArgs : EventArgs
16 | {
17 | public InvokerData Invoker { get; }
18 | public PlayResource PlayResource { get; }
19 | public AudioResource ResourceData => PlayResource.AudioResource;
20 | public PlayInfo? PlayInfo => PlayResource.PlayInfo;
21 | public string? SourceLink { get; }
22 |
23 | public PlayInfoEventArgs(InvokerData invoker, PlayResource playResource, string? sourceLink)
24 | {
25 | Invoker = invoker;
26 | PlayResource = playResource;
27 | SourceLink = sourceLink;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/TS3AudioBot/Audio/SongEndEventArgs.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 |
12 | namespace TS3AudioBot.Audio
13 | {
14 | public class SongEndEventArgs : EventArgs
15 | {
16 | public bool SongEndedByCallback { get; }
17 | public SongEndEventArgs(bool songEndedByCallback) { SongEndedByCallback = songEndedByCallback; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/TS3AudioBot/Audio/SongInfoChanged.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 |
12 | namespace TS3AudioBot.Audio
13 | {
14 | public class SongInfoChanged : EventArgs
15 | {
16 | public string? Title { get; set; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/TS3AudioBot/Audio/StallCheckPipe.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 | using TSLib.Audio;
12 |
13 | namespace TS3AudioBot.Audio
14 | {
15 | public class StallCheckPipe : IAudioPipe
16 | {
17 | private const uint StallCountInterval = 10;
18 | private const uint StallNoErrorCountMax = 5;
19 |
20 | public bool Active => OutStream?.Active ?? false;
21 | public IAudioPassiveConsumer? OutStream { get; set; }
22 |
23 | private bool isStall;
24 | private uint stallCount;
25 | private uint stallNoErrorCount;
26 |
27 | public StallCheckPipe()
28 | {
29 | isStall = false;
30 | stallCount = 0;
31 | }
32 |
33 | public void Write(Span data, Meta? meta)
34 | {
35 | if (OutStream is null) return;
36 |
37 | if (isStall)
38 | {
39 | // TODO maybe do time-cooldown instead of call-count-cooldown
40 | if (++stallCount % StallCountInterval == 0)
41 | {
42 | stallNoErrorCount++;
43 | if (stallNoErrorCount > StallNoErrorCountMax)
44 | {
45 | stallCount = 0;
46 | isStall = false;
47 | }
48 | }
49 | else
50 | {
51 | return;
52 | }
53 | }
54 |
55 | OutStream?.Write(data, meta);
56 | }
57 |
58 | public void SetStall()
59 | {
60 | stallNoErrorCount = 0;
61 | isStall = true;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/TS3AudioBot/Audio/StreamAudioPlayerSource.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 | using System.Threading.Tasks;
12 | using TSLib.Audio;
13 |
14 | namespace TS3AudioBot.Audio
15 | {
16 | public class StreamAudioPlayerSource : IPlayerSource, IAudioActiveConsumer
17 | {
18 | private bool hasFired = false;
19 |
20 | public IAudioPassiveProducer? InStream { get; set; }
21 | public TimeSpan? Length => null;
22 | public TimeSpan? Position => null;
23 |
24 | public event EventHandler? OnSongEnd;
25 | event EventHandler IPlayerSource.OnSongUpdated { add { } remove { } }
26 |
27 | public StreamAudioPlayerSource() { }
28 |
29 | public StreamAudioPlayerSource(IAudioPassiveProducer stream) : this()
30 | {
31 | InStream = stream;
32 | }
33 |
34 | public int Read(byte[] buffer, int offset, int length, out Meta? meta)
35 | {
36 | var stream = InStream;
37 | if (stream is null)
38 | {
39 | meta = default;
40 | return 0;
41 | }
42 |
43 | var read = stream.Read(buffer, offset, length, out meta);
44 | if (read == 0 && !hasFired)
45 | {
46 | hasFired = true;
47 | OnSongEnd?.Invoke(this, EventArgs.Empty);
48 | return 0;
49 | }
50 | return read;
51 | }
52 |
53 | public void Reset() => hasFired = false;
54 |
55 | public void Dispose() => InStream?.Dispose();
56 |
57 | public Task Seek(TimeSpan position) { throw new NotSupportedException(); }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/TS3AudioBot/CallerInfo.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | namespace TS3AudioBot
11 | {
12 | public class CallerInfo
13 | {
14 | /// Whether this call was initiated from the api.
15 | public bool ApiCall { get; }
16 | /// Skips all permission checks when set to true.
17 | public bool SkipRightsChecks { get; set; } = false;
18 | /// Counts execution token for a single call to prevent endless loops.
19 | public int CommandComplexityCurrent { get; set; } = 0;
20 | /// The maximum execution token count for a single call.
21 | public int CommandComplexityMax { get; set; } = 0;
22 | /// Whether the caller wants a colored output.
23 | public bool IsColor { get; set; }
24 |
25 | public CallerInfo(bool isApi)
26 | {
27 | ApiCall = isApi;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/TS3AudioBot/ClientCall.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using TSLib;
11 |
12 | namespace TS3AudioBot
13 | {
14 | public class ClientCall : InvokerData
15 | {
16 | /// The original unmodified string which was received by the client.
17 | public string TextMessage { get; }
18 |
19 | public ClientDbId? DatabaseId { get; }
20 | public ChannelId? ChannelId { get; }
21 | public ClientId? ClientId { get; }
22 | public string? NickName { get; }
23 | public ServerGroupId[]? ServerGroups { get; }
24 | public ChannelGroupId? ChannelGroup { get; }
25 | public TextMessageTargetMode? Visibiliy { get; internal set; }
26 |
27 | public ClientCall(Uid clientUid, string textMessage, ClientDbId? databaseId = null,
28 | ChannelId? channelId = null, ClientId? clientId = null, string? nickName = null,
29 | TextMessageTargetMode? visibiliy = null, ServerGroupId[]? serverGroups = null,
30 | ChannelGroupId? channelGroup = null) : base(clientUid)
31 | {
32 | TextMessage = textMessage;
33 | DatabaseId = databaseId;
34 | ChannelId = channelId;
35 | ClientId = clientId;
36 | NickName = nickName;
37 | Visibiliy = visibiliy;
38 | ServerGroups = serverGroups;
39 | ChannelGroup = channelGroup;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/Ast/AstCommand.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System.Collections.Generic;
11 | using System.Text;
12 |
13 | namespace TS3AudioBot.CommandSystem.Ast
14 | {
15 | internal class AstCommand : AstNode
16 | {
17 | public override AstType Type => AstType.Command;
18 |
19 | public List Parameter { get; } = new List();
20 |
21 | public AstCommand(string fullRequest) : base(fullRequest) { }
22 |
23 | public override void Write(StringBuilder strb, int depth)
24 | {
25 | strb.Space(depth);
26 | if (Parameter.Count == 0)
27 | {
28 | strb.Append("");
29 | }
30 | else
31 | {
32 | if (Parameter[0] is AstValue comName)
33 | strb.Append("!").Append(comName.Value);
34 | else
35 | strb.Append("");
36 |
37 | for (int i = 1; i < Parameter.Count; i++)
38 | {
39 | strb.AppendLine();
40 | Parameter[i].Write(strb, depth + 1);
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/Ast/AstError.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System.Text;
11 |
12 | namespace TS3AudioBot.CommandSystem.Ast
13 | {
14 | internal class AstError : AstNode
15 | {
16 | public override AstType Type => AstType.Error;
17 |
18 | public string Description { get; }
19 |
20 | public AstError(AstNode referenceNode, string description)
21 | : this(referenceNode.FullRequest, referenceNode.Position, referenceNode.Length, description) { }
22 |
23 | public AstError(string request, int pos, int len, string description) : base(request)
24 | {
25 | Position = pos;
26 | Length = len;
27 | Description = description;
28 | }
29 |
30 | public override void Write(StringBuilder strb, int depth)
31 | {
32 | strb.AppendLine(FullRequest);
33 | if (Position == 1) strb.Append('.');
34 | else if (Position > 1) strb.Append(' ', Position);
35 | strb.Append('~', Length).Append('^').AppendLine();
36 | strb.Append("Error: ").AppendLine(Description);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/Ast/AstNode.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System.Text;
11 |
12 | namespace TS3AudioBot.CommandSystem.Ast
13 | {
14 | public abstract class AstNode
15 | {
16 | public abstract AstType Type { get; }
17 |
18 | public string FullRequest { get; }
19 | public int Position { get; set; }
20 | public int Length { get; set; }
21 |
22 | protected AstNode(string fullRequest)
23 | {
24 | FullRequest = fullRequest;
25 | }
26 |
27 | public abstract void Write(StringBuilder strb, int depth);
28 | public sealed override string ToString()
29 | {
30 | var strb = new StringBuilder();
31 | Write(strb, 0);
32 | return strb.ToString();
33 | }
34 | }
35 |
36 | internal static class AstNodeExtensions
37 | {
38 | public const int SpacePerTab = 2;
39 | public static StringBuilder Space(this StringBuilder strb, int depth) => strb.Append(' ', depth * SpacePerTab);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/Ast/AstType.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | namespace TS3AudioBot.CommandSystem.Ast
11 | {
12 | public enum AstType
13 | {
14 | Command,
15 | Value,
16 | Error,
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/Ast/AstValue.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System.Text;
11 |
12 | namespace TS3AudioBot.CommandSystem.Ast
13 | {
14 | internal class AstValue : AstNode
15 | {
16 | private string? value;
17 | private string? tailString;
18 |
19 | public override AstType Type => AstType.Value;
20 | public StringType StringType { get; }
21 | public int TailLength { get; set; }
22 |
23 | public string Value
24 | {
25 | get => value ??= FullRequest.Substring(Position, Length);
26 | set { this.value = value; tailString = value; }
27 | }
28 |
29 | public string TailString
30 | {
31 | get
32 | {
33 | if (tailString is null)
34 | {
35 | if (TailLength == 0)
36 | tailString = FullRequest.Substring(Position);
37 | else
38 | tailString = FullRequest.Substring(Position, TailLength);
39 | }
40 | return tailString;
41 | }
42 | }
43 |
44 | public AstValue(string fullRequest, StringType stringType) : base(fullRequest)
45 | {
46 | StringType = stringType;
47 | }
48 |
49 | public override void Write(StringBuilder strb, int depth) => strb.Space(depth).Append(Value);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/Ast/StringType.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | namespace TS3AudioBot.CommandSystem.Ast
11 | {
12 | internal enum StringType
13 | {
14 | FreeString,
15 | QuotedString,
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/CommandAttribute.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 |
12 | namespace TS3AudioBot.CommandSystem
13 | {
14 | ///
15 | /// Marks a method as callable from the CommandSystem.
16 | /// The containing class must be registered in the CommandSystem to use this method.
17 | ///
18 | [AttributeUsage(AttributeTargets.Method, Inherited = false)]
19 | public sealed class CommandAttribute : Attribute
20 | {
21 | public string CommandNameSpace { get; }
22 | public string? OverrideHelpName { get; }
23 |
24 | public CommandAttribute(string commandNameSpace, string? overrideHelpName = null)
25 | {
26 | CommandNameSpace = commandNameSpace;
27 | OverrideHelpName = overrideHelpName;
28 | }
29 | }
30 |
31 | ///
32 | /// Gives an example on how to use this method.
33 | /// Can be used to clarify different functionality from various overloads.
34 | ///
35 | [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
36 | public sealed class UsageAttribute : Attribute
37 | {
38 | public string UsageSyntax { get; }
39 | public string UsageHelp { get; }
40 |
41 | public UsageAttribute(string syntax, string help)
42 | {
43 | UsageSyntax = syntax;
44 | UsageHelp = help;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/CommandResults/IAudioResourceResult.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using TS3AudioBot.ResourceFactories;
11 |
12 | namespace TS3AudioBot.CommandSystem.CommandResults
13 | {
14 | public interface IAudioResourceResult
15 | {
16 | AudioResource AudioResource { get; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/CommandResults/IWrappedResult.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | namespace TS3AudioBot.CommandSystem.CommandResults
11 | {
12 | public interface IWrappedResult
13 | {
14 | object? Content { get; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/CommandResults/PickObjectCommand.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System.Reflection;
11 |
12 | namespace TS3AudioBot.CommandSystem.CommandResults
13 | {
14 | public class Pick : IWrappedResult
15 | {
16 | private readonly string pickPath;
17 | private readonly T baseObj;
18 | private bool isPicked;
19 | private object? pickedValue;
20 |
21 | public object? Content
22 | {
23 | get
24 | {
25 | if (!isPicked)
26 | {
27 | isPicked = true;
28 | pickedValue = null;
29 | pickedValue = DoPick();
30 | }
31 | return pickedValue;
32 | }
33 | }
34 |
35 | public Pick(T obj, string pickPath)
36 | {
37 | baseObj = obj;
38 | this.pickPath = pickPath;
39 | }
40 |
41 | private object? DoPick()
42 | {
43 | if (baseObj == null)
44 | return null; // TODO maybe error ?
45 | if (string.IsNullOrEmpty(pickPath))
46 | return baseObj;
47 | var type = baseObj.GetType();
48 | var prop = type.GetProperty(pickPath, BindingFlags.Public | BindingFlags.Instance);
49 | if (prop is null)
50 | throw new CommandException("Property not found" /* TODO LOC */);
51 | return prop.GetValue(baseObj);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/CommandResults/TailString.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | namespace TS3AudioBot.CommandSystem.CommandResults
11 | {
12 | public class TailString : IWrappedResult
13 | {
14 | public string Content { get; }
15 | public string Tail { get; }
16 | object? IWrappedResult.Content => Content;
17 |
18 | public TailString(string contentArg, string tailArg)
19 | {
20 | Content = contentArg;
21 | Tail = tailArg;
22 | }
23 |
24 | public override string ToString() => Content;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/CommandSystemExtensions.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 | using System.Collections.Generic;
12 | using System.Threading.Tasks;
13 | using TS3AudioBot.Algorithm;
14 | using TS3AudioBot.CommandSystem.Commands;
15 | using TS3AudioBot.Dependency;
16 |
17 | namespace TS3AudioBot.CommandSystem
18 | {
19 | public static class CommandSystemExtensions
20 | {
21 | public static IFilter GetFilter(this IInjector injector)
22 | {
23 | if (injector.TryGet(out var filter))
24 | return filter;
25 | return Filter.DefaultFilter;
26 | }
27 |
28 | public static Lazy GetFilterLazy(this IInjector injector)
29 | => new Lazy(() => injector.GetFilter(), false);
30 |
31 | public static async ValueTask ExecuteToString(this ICommand com, ExecutionInformation info, IReadOnlyList arguments)
32 | {
33 | var res = await com.Execute(info, arguments);
34 | return res?.ToString() ?? "";
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/CommandSystemTypes.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2017 TS3AudioBot contributors
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the Open Software License v. 3.0
5 | //
6 | // You should have received a copy of the Open Software License along with this
7 | // program. If not, see .
8 |
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Linq;
12 | using TS3AudioBot.CommandSystem.CommandResults;
13 | using TSLib;
14 |
15 | namespace TS3AudioBot.CommandSystem
16 | {
17 | public static class CommandSystemTypes
18 | {
19 | ///
20 | /// The order of types, the first item has the highest priority,
21 | /// items not in the list have higher priority as they are special types.
22 | ///
23 | public static readonly Type[] TypeOrder = {
24 | typeof(bool),
25 | typeof(sbyte), typeof(byte),
26 | typeof(short), typeof(ushort),
27 | typeof(int), typeof(uint),
28 | typeof(long), typeof(ulong),
29 | typeof(float), typeof(double),
30 | typeof(TimeSpan), typeof(DateTime),
31 | typeof(string) };
32 | public static readonly HashSet BasicTypes = new HashSet(TypeOrder);
33 |
34 | public static readonly HashSet AdvancedTypes = new HashSet(new Type[] {
35 | typeof(IAudioResourceResult),
36 | typeof(System.Collections.IEnumerable),
37 | typeof(ResourceFactories.AudioResource),
38 | typeof(History.AudioLogEntry),
39 | typeof(Playlists.PlaylistItem),
40 | }.Concat(TsTypes.All));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/TS3AudioBot/CommandSystem/Commands/AliasCommand.cs:
--------------------------------------------------------------------------------
1 | // TS3AudioBot - An advanced Musicbot for Teamspeak 3
2 | // Copyright (C) 2017 TS3AudioBot contributors
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the Open Software License v. 3.0
6 | //
7 | // You should have received a copy of the Open Software License along with this
8 | // program. If not, see .
9 |
10 | using System;
11 | using System.Collections.Generic;
12 | using System.Linq;
13 | using System.Threading.Tasks;
14 | using TS3AudioBot.Dependency;
15 |
16 | namespace TS3AudioBot.CommandSystem.Commands
17 | {
18 | public class AliasCommand : ICommand
19 | {
20 | private readonly ICommand aliasCommand;
21 | public string AliasString { get; }
22 |
23 | public AliasCommand(string command)
24 | {
25 | var ast = CommandParser.ParseCommandRequest(command);
26 | aliasCommand = CommandManager.AstToCommandResult(ast);
27 | AliasString = command;
28 | }
29 |
30 | public async ValueTask