Browse Source

iZpl additonal feature for autotrigger of ch!p bot in discord
LogBLockHeatMapper perf tweaks
TM-Exchange url grabber

LH 4 years ago
parent
commit
40f0f3e3da
45 changed files with 2363 additions and 424 deletions
  1. 118 0
      F3Enabler/.gitignore
  2. 21 0
      F3Enabler/LICENSE
  3. 77 0
      F3Enabler/build.gradle
  4. 14 0
      F3Enabler/gradle.properties
  5. BIN
      F3Enabler/gradle/wrapper/gradle-wrapper.jar
  6. 5 0
      F3Enabler/gradle/wrapper/gradle-wrapper.properties
  7. 185 0
      F3Enabler/gradlew
  8. 104 0
      F3Enabler/gradlew.bat
  9. 10 0
      F3Enabler/settings.gradle
  10. 10 0
      F3Enabler/src/main/java/de/nplusc/izc/fthreenabler/FThreeNabler.java
  11. 18 0
      F3Enabler/src/main/java/de/nplusc/izc/fthreenabler/client/FThreeNablerClient.java
  12. 14 0
      F3Enabler/src/main/java/de/nplusc/izc/fthreenabler/mixin/GamemodeScreenMixin.java
  13. 15 0
      F3Enabler/src/main/java/de/nplusc/izc/fthreenabler/mixin/KeyboardMixin.java
  14. 15 0
      F3Enabler/src/main/resources/FThreeNabler.mixins.json
  15. 26 0
      F3Enabler/src/main/resources/fabric.mod.json
  16. 2 2
      LogBlockHeatMapper/build.gradle
  17. 21 0
      LogBlockHeatMapper/src/main/java/de/nplusc/izc/logblockheatmapper/EntryPoint.java
  18. 40 11
      LogBlockHeatMapper/src/main/java/de/nplusc/izc/logblockheatmapper/LogBlockHeatmapper.java
  19. 51 58
      LogBlockHeatMapper/src/main/java/de/nplusc/izc/logblockheatmapper/LogBlockHeatmapperRegionTrimmer.java
  20. 3 0
      TM-ExchangeURLGrabber/.gitignore
  21. 150 0
      TM-ExchangeURLGrabber/Program.cs
  22. 13 0
      TM-ExchangeURLGrabber/TM-ExchangeURLGrabber.csproj
  23. 25 0
      TM-ExchangeURLGrabber/TM-ExchangeURLGrabber.sln
  24. 3 1
      iZpl/build.gradle
  25. BIN
      iZpl/lib/jar-loader.jar
  26. BIN
      iZpl/lib/jnafilechooser-api-0.1-SNAPSHOT.jar
  27. BIN
      iZpl/lib/jnafilechooser-win32-0.1-SNAPSHOT.jar
  28. 1 1
      iZpl/src/main/java/de/nplusc/izc/iZpl/API/IZPLApi.java
  29. 15 1
      iZpl/src/main/java/de/nplusc/izc/iZpl/API/PlayListEditAPI.java
  30. 47 43
      iZpl/src/main/java/de/nplusc/izc/iZpl/API/Plugin.java
  31. 14 7
      iZpl/src/main/java/de/nplusc/izc/iZpl/API/PluginManager.java
  32. 1 0
      iZplPlugins/discordjukebox/.gitignore
  33. 19 0
      iZplPlugins/discordjukebox/build.gradle
  34. 60 0
      iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/Configuration.java
  35. 220 0
      iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/Discord.java
  36. 109 0
      iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/JukeBox.form
  37. 264 0
      iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/JukeBox.java
  38. 117 0
      iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/UI.form
  39. 269 0
      iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/UI.java
  40. BIN
      iZplPlugins/discordjukebox/src/main/resources/binaries/windows/ffmpeg.exe
  41. 11 0
      iZplPlugins/discordjukebox/src/main/resources/plugin.yml
  42. 239 235
      izpl-shared/src/main/java/de/nplusc/izc/iZpl/API/shared/MultiPlayListItem.java
  43. 36 35
      izpl-shared/src/main/java/de/nplusc/izc/iZpl/API/shared/PlayListItem.java
  44. 1 1
      settings.gradle
  45. 0 29
      spungit_deathtimer/build.gradle

+ 118 - 0
F3Enabler/.gitignore

@@ -0,0 +1,118 @@
+# User-specific stuff
+.idea/
+
+*.iml
+*.ipr
+*.iws
+
+# IntelliJ
+out/
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+# Windows thumbnail cache files
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+.gradle
+build/
+
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# Cache of project
+.gradletasknamecache
+
+**/build/
+
+# Common working directory
+run/
+
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar

+ 21 - 0
F3Enabler/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2020 
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 77 - 0
F3Enabler/build.gradle

@@ -0,0 +1,77 @@
+plugins {
+    id 'fabric-loom' version '0.5-SNAPSHOT'
+    id 'maven-publish'
+}
+
+sourceCompatibility = JavaVersion.VERSION_1_8
+targetCompatibility = JavaVersion.VERSION_1_8
+
+archivesBaseName = project.archives_base_name
+version = project.mod_version
+group = project.maven_group
+
+dependencies {
+    //to change the versions see the gradle.properties file
+    minecraft "com.mojang:minecraft:${project.minecraft_version}"
+    mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
+    modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
+
+    // Fabric API. This is technically optional, but you probably want it anyway.
+    modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
+
+    // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
+    // You may need to force-disable transitiveness on them.
+}
+
+processResources {
+    inputs.property "version", project.version
+
+    from(sourceSets.main.resources.srcDirs) {
+        include "fabric.mod.json"
+        expand "version": project.version
+    }
+
+    from(sourceSets.main.resources.srcDirs) {
+        exclude "fabric.mod.json"
+    }
+}
+
+// ensure that the encoding is set to UTF-8, no matter what the system default is
+// this fixes some edge cases with special characters not displaying correctly
+// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
+tasks.withType(JavaCompile) {
+    options.encoding = "UTF-8"
+}
+
+// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
+// if it is present.
+// If you remove this task, sources will not be generated.
+task sourcesJar(type: Jar, dependsOn: classes) {
+    classifier = "sources"
+    from sourceSets.main.allSource
+}
+
+jar {
+    from "LICENSE"
+}
+
+// configure the maven publication
+publishing {
+    publications {
+        mavenJava(MavenPublication) {
+            // add all the jars that should be included when publishing to maven
+            artifact(remapJar) {
+                builtBy remapJar
+            }
+            artifact(sourcesJar) {
+                builtBy remapSourcesJar
+            }
+        }
+    }
+
+    // select the repositories you want to publish to
+    repositories {
+        // uncomment to publish to the local maven
+        // mavenLocal()
+    }
+}

+ 14 - 0
F3Enabler/gradle.properties

@@ -0,0 +1,14 @@
+# Done to increase the memory available to gradle.
+org.gradle.jvmargs=-Xmx1G
+# Fabric Properties
+# check these on https://modmuss50.me/fabric.html
+minecraft_version=1.16.4
+yarn_mappings=1.16.4+build.7
+loader_version=0.10.8
+# Mod Properties
+mod_version=1.0-SNAPSHOT
+maven_group=de.nplusc.izc
+archives_base_name=FThreeNabler
+# Dependencies
+# check this on https://modmuss50.me/fabric.html
+fabric_version=0.25.1+build.416-1.16

BIN
F3Enabler/gradle/wrapper/gradle-wrapper.jar


+ 5 - 0
F3Enabler/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists

+ 185 - 0
F3Enabler/gradlew

@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=`expr $i + 1`
+    done
+    case $i in
+        0) set -- ;;
+        1) set -- "$args0" ;;
+        2) set -- "$args0" "$args1" ;;
+        3) set -- "$args0" "$args1" "$args2" ;;
+        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"

+ 104 - 0
F3Enabler/gradlew.bat

@@ -0,0 +1,104 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

+ 10 - 0
F3Enabler/settings.gradle

@@ -0,0 +1,10 @@
+pluginManagement {
+    repositories {
+        jcenter()
+        maven {
+            name = 'Fabric'
+            url = 'https://maven.fabricmc.net/'
+        }
+        gradlePluginPortal()
+    }
+}

+ 10 - 0
F3Enabler/src/main/java/de/nplusc/izc/fthreenabler/FThreeNabler.java

@@ -0,0 +1,10 @@
+package de.nplusc.izc.fthreenabler;
+
+import net.fabricmc.api.ModInitializer;
+
+public class FThreeNabler implements ModInitializer {
+    @Override
+    public void onInitialize() {
+
+    }
+}

+ 18 - 0
F3Enabler/src/main/java/de/nplusc/izc/fthreenabler/client/FThreeNablerClient.java

@@ -0,0 +1,18 @@
+package de.nplusc.izc.fthreenabler.client;
+
+import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.Keyboard;
+import net.minecraft.client.gui.screen.GameModeSelectionScreen;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.ModifyArg;
+
+@Environment(EnvType.CLIENT)
+public class FThreeNablerClient implements ClientModInitializer {
+    @Override
+    public void onInitializeClient() {
+
+    }
+}

+ 14 - 0
F3Enabler/src/main/java/de/nplusc/izc/fthreenabler/mixin/GamemodeScreenMixin.java

@@ -0,0 +1,14 @@
+package de.nplusc.izc.fthreenabler.mixin;
+
+import net.minecraft.client.gui.screen.GameModeSelectionScreen;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.ModifyArg;
+
+@Mixin(GameModeSelectionScreen.class)
+abstract class GamemodeScreenMixin {
+    @ModifyArg(method = "apply(Lnet/minecraft/client/MinecraftClient;Ljava/util/Optional;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;hasPermissionLevel(I)Z"))
+    private static int injected(int x) {
+        return 0;
+    }
+}

+ 15 - 0
F3Enabler/src/main/java/de/nplusc/izc/fthreenabler/mixin/KeyboardMixin.java

@@ -0,0 +1,15 @@
+package de.nplusc.izc.fthreenabler.mixin;
+
+import net.minecraft.client.Keyboard;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.ModifyArg;
+
+@Mixin(Keyboard.class)
+public class KeyboardMixin {
+    @ModifyArg(method = "processF3(I)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;hasPermissionLevel(I)Z"))
+    private int injected(int x) {
+        return 0;
+    }
+}
+

+ 15 - 0
F3Enabler/src/main/resources/FThreeNabler.mixins.json

@@ -0,0 +1,15 @@
+{
+  "required": true,
+  "minVersion": "0.8",
+  "package": "de.nplusc.izc.fthreenabler.mixin",
+  "compatibilityLevel": "JAVA_8",
+  "mixins": [
+  ],
+  "client": [
+    "GamemodeScreenMixin",
+    "KeyboardMixin"
+  ],
+  "injectors": {
+    "defaultRequire": 1
+  }
+}

+ 26 - 0
F3Enabler/src/main/resources/fabric.mod.json

@@ -0,0 +1,26 @@
+{
+  "schemaVersion": 1,
+  "id": "fthreenabler",
+  "version": "${version}",
+  "name": "FThreeNabler",
+  "description": "",
+  "authors": [],
+  "contact": {},
+  "license": "MIT",
+  "environment": "client",
+  "entrypoints": {
+    "client": [
+      "de.nplusc.izc.fthreenabler.client.FThreeNablerClient"
+    ],
+    "main": [
+      "de.nplusc.izc.fthreenabler.FThreeNabler"
+    ]
+  },
+  "mixins": [
+    "FThreeNabler.mixins.json"
+  ],
+  "depends": {
+    "fabricloader": ">=0.10.8",
+    "minecraft": ">=1.16"
+  }
+}

+ 2 - 2
LogBlockHeatMapper/build.gradle

@@ -6,14 +6,14 @@ apply plugin: 'application'
 
 sourceCompatibility = 1.8
 version = 'SNAPSHOT'
-mainClassName = 'de.nplusc.izc.logblockheatmapper.LogBlockHeatmapperRegionTrimmer'
+mainClassName = 'de.nplusc.izc.logblockheatmapper.EntryPoint'
 
 
 jar{
 	manifest{
 		attributes 'Implementation-Title': 'iZLbHeatmapper',
 					'Implementation-Version': 'SNAPSHOT',
-					'Main-Class': 'de.nplusc.izc.logblockheatmapper.LogBlockHeatmapper'
+					'Main-Class': 'de.nplusc.izc.logblockheatmapper.EntryPoint'
 					
 	}
 }

+ 21 - 0
LogBlockHeatMapper/src/main/java/de/nplusc/izc/logblockheatmapper/EntryPoint.java

@@ -0,0 +1,21 @@
+package de.nplusc.izc.logblockheatmapper;
+
+import java.util.Arrays;
+
+public class EntryPoint
+{
+    public static void main(String[] args)throws Exception
+    {
+        String mode = args[0];
+        args = Arrays.copyOfRange(args,1,args.length);
+
+        if(mode.equalsIgnoreCase("heat"))
+        {
+            LogBlockHeatmapper.main(args);
+        }
+        if(mode.equalsIgnoreCase("region"))
+        {
+            LogBlockHeatmapperRegionTrimmer.main(args);
+        }
+    }
+}

+ 40 - 11
LogBlockHeatMapper/src/main/java/de/nplusc/izc/logblockheatmapper/LogBlockHeatmapper.java

@@ -18,12 +18,17 @@
 
 package de.nplusc.izc.logblockheatmapper;
 
-import java.awt.Color;
-import java.awt.GradientPaint;
-import java.awt.Graphics2D;
+import ar.com.hjg.pngj.ImageInfo;
+import ar.com.hjg.pngj.ImageLineHelper;
+import ar.com.hjg.pngj.ImageLineInt;
+import ar.com.hjg.pngj.PngWriter;
+
+import java.awt.*;
+import java.awt.geom.Point2D;
 import java.awt.image.BufferedImage;
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.FileReader;
 import javax.imageio.ImageIO;
 
@@ -60,11 +65,21 @@ public class LogBlockHeatmapper
             }
         }
         int size = Integer.valueOf(args[1]);
-        dataField = new int[size][size];
-        GradientPaint p = new GradientPaint(0, 0, Color.blue, 1023, 0, Color.red);
+
+
+        Point2D start = new Point2D.Float(0, 0);
+        Point2D end = new Point2D.Float(1023, 0);
+
+        Color[] colors = {Color.blue, Color.green, Color.YELLOW, Color.RED};
+        float[] steps = {0.0f,0.2f,0.6f,1.0f};
+        Paint p = new LinearGradientPaint(start,end,steps,colors);
         Graphics2D lw = (Graphics2D) gradient.getGraphics();
         lw.setPaint(p);
         lw.fillRect(0, 0, 1023, 1);
+        ImageIO.write(gradient,"png",new File("Debug.png"));
+        
+        System.out.println("Initializing Datastructures, this may take a while....");
+        dataField = new int[size][size];
         BufferedReader br = new BufferedReader(new FileReader(args[0]));
         br.lines().forEach((xx)->
         {
@@ -92,10 +107,10 @@ public class LogBlockHeatmapper
             if(x<size&&x>=0&&y<size&&y>=0&&register)
             {
                 //minecraftlogik.....
-                dataField[x][y]+=1;
-                if(dataField[x][y]>max)
+                dataField[y][x]+=1;
+                if(dataField[y][x]>max)
                 {
-                    max=dataField[x][y];
+                    max=dataField[y][x];
                     maxx= Integer.parseInt(xes[4]);
                     maxy = Integer.parseInt(xes[6]);
                 }
@@ -117,14 +132,25 @@ public class LogBlockHeatmapper
         //bw.newLine();
         //bw.write("255");
         //bw.newLine();
-        BufferedImage bi = new BufferedImage(size,size, BufferedImage.TYPE_4BYTE_ABGR);
+        //BufferedImage bi = new BufferedImage(size,size, BufferedImage.TYPE_4BYTE_ABGR);
         //SELECT id, replaced, `type`, `data`, x, y, z 
         //FROM `lb-surv`
         //INTO OUTFILE 'D:/emc2/arca_slash/database/lbcrunchsurvival.csv';
 
+        ImageInfo imi = new ImageInfo(dataField.length, dataField.length, 8, false); // 8 bits per channel, no alpha
+        // open image for writing to a output stream
+        PngWriter png = new PngWriter(new FileOutputStream("map.png"), imi);
+        // add some optional metadata (chunks)
+        png.getMetadata().setDpi(100.0);
+        png.getMetadata().setTimeNow(0); // 0 seconds fron now = now
+
+
+
         //0-49 1 stufe=1 farbschritt 50 -1049: 10 stufen pro farbschritt: rest gleichmäßig aufgeteilt bis maximum
         for (int i = 0; i < dataField.length; i++)
         {
+
+            ImageLineInt iline = new ImageLineInt(imi);
             int[] is = dataField[i];
             for (int j = 0; j < is.length; j++)
             {
@@ -184,7 +210,8 @@ public class LogBlockHeatmapper
                         }
                     }
                 }
-                bi.setRGB(i, j, color);
+
+                ImageLineHelper.setPixelRGB8(iline, j,color);
                 //bi.setRGB(i,j,k<<16&k<<8&k);
                 //if(j<19999)
                // {
@@ -193,10 +220,12 @@ public class LogBlockHeatmapper
             }
             //if(i<19999)
                // bw.newLine();
+            png.writeRow(iline);
             System.out.print(i+"lines rasterized\r");
         }
         //bw.close();
-        ImageIO.write(bi, "png",new File( "map.png"));
+        png.end();
+        //ImageIO.write(bi, "png",new File( "map.png"));
     }
     
 }

+ 51 - 58
LogBlockHeatMapper/src/main/java/de/nplusc/izc/logblockheatmapper/LogBlockHeatmapperRegionTrimmer.java

@@ -30,6 +30,9 @@ import java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
 import java.io.*;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
 import javax.imageio.ImageIO;
 
 /**
@@ -56,9 +59,9 @@ enum RegionState
 public class LogBlockHeatmapperRegionTrimmer
 {
       //x  y
-    static BlockState[ ][ ] dataField ;
+    static int[ ][ ] dataField ;
     
-    static HashMap<String,RegionState> keepRegions = new HashMap<>();
+    static Map<String,RegionState> keepRegions = new TreeMap<>();
     
     static int radius=0;
     
@@ -116,7 +119,7 @@ public class LogBlockHeatmapperRegionTrimmer
         
         
         radius = Integer.valueOf(args[1]);
-        dataField = new BlockState[radius*2][radius*2];
+        dataField = new int[radius*2][radius*2];
 
         int regionBase = radius/512;
         int regionRemainder = radius%512;
@@ -154,7 +157,7 @@ public class LogBlockHeatmapperRegionTrimmer
         {
             for(int j=0;j<dataField.length;j++)
             {
-                dataField[i][j]=BlockState.NONE;
+                dataField[i][j]=BlockState.NONE.ordinal();
             }
             System.out.print(i+" Preparation Data Lines\r");
         }
@@ -187,16 +190,16 @@ public class LogBlockHeatmapperRegionTrimmer
                             if((y+j)<(radius*2)&&(y+j)>0)
                             {
                                 //only switching NONE to BUFFER
-                                if(dataField[x+i][y+j]==BlockState.NONE)
+                                if(dataField[y+j][x+i]==BlockState.NONE.ordinal())
                                 {
-                                    dataField[x+i][y+j]=BlockState.BUFFER;
+                                    dataField[y+j][x+i]=BlockState.BUFFER.ordinal();
                                     setRegion(x+i-radius, y+i-radius, RegionState.KEEP);
                                 }
                             }
                         }
                     }
                 }
-                dataField[x][y]=BlockState.ACTIVITY;
+                dataField[y][x]=BlockState.ACTIVITY.ordinal();
                 setRegion(x-radius, y-radius, RegionState.KEEP);
                 
             }
@@ -253,77 +256,67 @@ public class LogBlockHeatmapperRegionTrimmer
 
         ImageInfo imi = new ImageInfo(dataField.length, dataField.length, 8, false); // 8 bits per channel, no alpha
         // open image for writing to a output stream
-        PngWriter png = new PngWriter(new FileOutputStream("map.png"), imi);
+        PngWriter png = new PngWriter(new FileOutputStream("map_rg.png"), imi);
         // add some optional metadata (chunks)
         png.getMetadata().setDpi(100.0);
         png.getMetadata().setTimeNow(0); // 0 seconds fron now = now
 
-        
-        
+
         //0-49 1 stufe=1 farbschritt 50 -1049: 10 stufen pro farbschritt: rest gleichmäßig aufgeteilt bis maximum
-        for (int i = 0; i < dataField.length; i++)
-        {
-            BlockState[] is = dataField[i];
+        for (int i = 0; i < dataField.length; i++) {
+            int[] is = dataField[i];
             ImageLineInt iline = new ImageLineInt(imi);
 
-            for (int j = 0; j < is.length; j++)
-            {
-                int color=Color.white.getRGB();
-                BlockState k = is[j];
+            for (int j = 0; j < is.length; j++) {
+                int color = Color.white.getRGB();
+                BlockState k = BlockState.values()[is[j]];
 
-                switch(k)
-                {
+                switch (k) {
                     case NONE:
-                        int rx = (int)Math.floor((i-radius)/512.0);
-                        int ry = (int)Math.floor((j-radius)/512.0);
-                        
-                        if((i==radius+coreRadius||j==radius-coreRadius)||
-                            (j==radius+coreRadius||j==radius-coreRadius))
-                        {
-                            color=coreEdge.getRGB();
-                        }
-                        else
-                        {
-                            boolean grid = (rx+ry)%2==0;
-                            
-                            RegionState s = keepRegions.get(("r."+rx+"."+ry+".mca"));
-                            if(s==null)
-                            {
-                                s=RegionState.REMOVE;
+                        int rx = (int) Math.floor((j - radius) / 512.0);
+                        int ry = (int) Math.floor((i - radius) / 512.0);
+
+                        if ((i == radius + coreRadius || j == radius - coreRadius) ||
+                                (j == radius + coreRadius || j == radius - coreRadius)) {
+                            color = coreEdge.getRGB();
+                        } else {
+                            boolean grid = (rx + ry) % 2 == 0;
+
+                            RegionState s = keepRegions.get(("r." + rx + "." + ry + ".mca"));
+                            if (s == null) {
+                                s = RegionState.REMOVE;
                             }
-                            switch(s)
-                            {
+                            switch (s) {
                                 case REMOVE:
-                                    color=(grid?removeA:removeB).getRGB();
+                                    color = (grid ? removeA : removeB).getRGB();
                                     break;
                                 case CORE:
-                                    color=(grid?keepCoreA:keepCoreB).getRGB();
+                                    color = (grid ? keepCoreA : keepCoreB).getRGB();
                                     break;
                                 case KEEP:
-                                    color=(grid?keepA:keepB).getRGB();
+                                    color = (grid ? keepA : keepB).getRGB();
                                     break;
                                 case WATERIZE:
-                                    color=(grid?waterA:waterB).getRGB();
+                                    color = (grid ? waterA : waterB).getRGB();
                                     break;
                             }
                         }
                         break;
                     case BUFFER:
-                        color= activityBuffer.getRGB();
+                        color = activityBuffer.getRGB();
                         break;
                     case ACTIVITY:
-                        color= activity.getRGB();
+                        color = activity.getRGB();
                         break;
                 }
 
-                ImageLineHelper.setPixelRGB8(iline, j,color);
+                ImageLineHelper.setPixelRGB8(iline, j, color);
             }
             png.writeRow(iline);
-            System.out.print(i+"lines rasterized\r");
+            System.out.print(i + "lines rasterized\r");
         }
         png.end();
         System.out.println();
-
         PrintStream fileActions;
 
         try {
@@ -332,28 +325,28 @@ public class LogBlockHeatmapperRegionTrimmer
             System.out.println("mkdir oldChunks");
             fileActions.println("mkdir oldChunksWaterize");
             System.out.println("mkdir oldChunksWaterize");
-            keepRegions.entrySet().forEach(k->
+            keepRegions.forEach((k,v)->
             {
-                switch(k.getValue())
+                switch(v)
                 {
 
                     case REMOVE:
-                        fileActions.println("mv "+k.getKey()+" oldChunks/");
-                        System.out.println("mv "+k.getKey()+" oldChunks/");
+                        fileActions.println("mv "+k+" oldChunks/");
+                        System.out.println("mv "+k+" oldChunks/");
                         break;
                     case CORE:
-                        fileActions.println("echo "+k.getKey()+" is keepCore");
-                        System.out.println("echo "+k.getKey()+" is keepCore");
+                        fileActions.println("echo "+k+" is keepCore");
+                        System.out.println("echo "+k+" is keepCore");
                         break;
                     case KEEP:
-                        fileActions.println("echo "+k.getKey()+" is keep");
-                        System.out.println("echo "+k.getKey()+" is keep");
+                        fileActions.println("echo "+k+" is keep");
+                        System.out.println("echo "+k+" is keep");
                         break;
                     case WATERIZE:
-                        fileActions.println("mv "+k.getKey()+" oldChunksWaterize/");
-                        System.out.println("mv "+k.getKey()+" oldChunksWaterize/");
-                        fileActions.println("mv waterize/"+k.getKey()+" ./");
-                        System.out.println("mv waterize/"+k.getKey()+" ./");
+                        fileActions.println("mv "+k+" oldChunksWaterize/");
+                        System.out.println("mv "+k+" oldChunksWaterize/");
+                        fileActions.println("mv waterize/"+k+" ./");
+                        System.out.println("mv waterize/"+k+" ./");
                         break;
                 }
             });

+ 3 - 0
TM-ExchangeURLGrabber/.gitignore

@@ -0,0 +1,3 @@
+bin
+obj
+.vs

+ 150 - 0
TM-ExchangeURLGrabber/Program.cs

@@ -0,0 +1,150 @@
+using HtmlAgilityPack;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace TM_ExchangeURLGrabber
+{
+    class Program
+    {
+        private static readonly HttpClient client = new HttpClient();
+        private static readonly string magicXpath = "//input";
+        private static readonly string magicXpath2 = "//select";
+        private static readonly string parameter = "_ctl3$PageTracks";
+        private static readonly string template = "goto|{0}|20";
+        private static readonly int maxPages = 5; //MAXINT on production run
+        private static string[] prefixes = { "united", "tmnforever", "nations", "sunrise", "original" };
+
+
+        static async Task Main(string[] args)
+        {
+            foreach(var prefix in prefixes)
+            {
+                await Process(prefix);
+            }
+        }
+
+        static async Task Process(string prefix)
+        {
+            string html = "";
+            var urlsFound = new List<string>();
+            //entrypoint: https://united.tm-exchange.com/main.aspx?action=tracksearch
+            var response = await client.GetAsync("https://"+prefix+".tm-exchange.com/main.aspx?action=tracksearch");
+
+            var responseString = await response.Content.ReadAsStringAsync();
+
+            var doc = new HtmlDocument();
+            doc.LoadHtml(responseString);
+            var traxxetracks = int.Parse(doc.DocumentNode.SelectSingleNode("//*[contains(@id,'ShowMatches')]").InnerText.Replace(",", ""));
+
+            var postDict = parseForFormCrap(doc);
+            Console.WriteLine(traxxetracks);
+            var pages = traxxetracks / 20.0d;
+            var pagesCeiled = (int)Math.Ceiling(pages); //decimals should be gone now;
+            Console.WriteLine(pages + "|" + pagesCeiled);
+            for(int i=1;i<Math.Min(pagesCeiled,maxPages);i++)
+            {
+                var temp = parseUrlMagic(doc,prefix);
+                Console.WriteLine(temp.Count);
+                
+                urlsFound.AddRange(temp);
+                var magic = string.Format(template, (i + 1) + "");
+                Console.WriteLine(magic);
+                //postDict.Add(parameter, magic);
+
+                postDict.Add("__EVENTTARGET", parameter);
+                postDict.Add("__EVENTARGUMENT", magic);
+
+                Console.WriteLine("############ BEGIN P0ST################");
+                
+                foreach(var elem in postDict)
+                {
+                    Console.WriteLine(elem.Key+"|||||"+elem.Value);
+                }
+
+                Console.WriteLine("############ END P0ST################");
+                if(i+1 == Math.Min(pagesCeiled, maxPages))
+                {
+                    break;
+                }
+                response = await client.PostAsync("https://" + prefix + ".tm-exchange.com/main.aspx?action=auto#auto", new FormUrlEncodedContent(postDict));
+
+                responseString = await response.Content.ReadAsStringAsync();
+
+                doc.LoadHtml(responseString);
+                Console.WriteLine(responseString);
+                postDict = parseForFormCrap(doc);
+
+            }
+
+            Console.WriteLine(urlsFound.Count);
+
+            foreach (var elem in urlsFound)
+            {
+                Console.WriteLine(elem);
+            }
+            File.WriteAllLines("./"+prefix+".txt",urlsFound);
+        }
+
+
+        private static List<string> parseUrlMagic(HtmlDocument doc, string prefix)
+        {
+            var returnVal = new List<string>();
+            // 
+            var nodes = doc.DocumentNode.SelectNodes("//tr[contains(@class, 'WindowTableCell1') or contains(@class, 'WindowTableCell2')]/td[1]/a[2]");
+
+            foreach(var node in nodes)
+            {
+                returnVal.Add("https://" + prefix + ".tm-exchange.com/" + node.Attributes["href"].Value);
+                Console.WriteLine("https://" + prefix + ".tm-exchange.com/" + node.Attributes["href"].Value);
+            }
+
+            return returnVal;
+        }
+
+
+        private static Dictionary<string,string> parseForFormCrap(HtmlDocument doc)
+        {
+            var nodes = doc.DocumentNode.SelectNodes(magicXpath);
+            var postValues = new Dictionary<string, string>();
+
+            foreach (var node in nodes)
+            {
+                postValues.Add(node.Attributes["name"].Value, node.Attributes["value"]?.Value ?? ((node.Attributes["checked"]?.Value) == "checked" ? "on" : ""));
+                Console.WriteLine(node.Attributes["name"].Value);
+                Console.WriteLine(node.Attributes["value"]?.Value ?? ((node.Attributes["checked"]?.Value) == "checked" ? "on" : ""));
+            }
+
+            nodes = doc.DocumentNode.SelectNodes(magicXpath2);
+            foreach (var node in nodes)
+            {
+                Console.WriteLine(node.InnerHtml);
+                var selection = node.SelectSingleNode(".//option[@selected]")?? node.SelectSingleNode(".//option[1]");
+
+                postValues.Add(node.Attributes["name"].Value, selection.Attributes["value"]?.Value);
+                Console.WriteLine(node.Attributes["name"].Value);
+                Console.WriteLine(selection.Attributes["value"]?.Value);
+
+            }
+            return postValues;
+        }
+    }
+}
+
+
+/*
+ var values = new Dictionary<string, string>
+{
+    { "thing1", "hello" },
+    { "thing2", "world" }
+};
+
+var content = new FormUrlEncodedContent(values);
+
+var response = await client.PostAsync("http://www.example.com/recepticle.aspx", content);
+
+var responseString = await response.Content.ReadAsStringAsync();
+ 
+ */

+ 13 - 0
TM-ExchangeURLGrabber/TM-ExchangeURLGrabber.csproj

@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net5.0</TargetFramework>
+    <RootNamespace>TM_ExchangeURLGrabber</RootNamespace>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="HtmlAgilityPack" Version="1.11.32" />
+  </ItemGroup>
+
+</Project>

+ 25 - 0
TM-ExchangeURLGrabber/TM-ExchangeURLGrabber.sln

@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31129.286
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TM-ExchangeURLGrabber", "TM-ExchangeURLGrabber.csproj", "{0E19FB29-2DE2-4E84-BDE4-CD6CFB7EA952}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{0E19FB29-2DE2-4E84-BDE4-CD6CFB7EA952}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0E19FB29-2DE2-4E84-BDE4-CD6CFB7EA952}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0E19FB29-2DE2-4E84-BDE4-CD6CFB7EA952}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0E19FB29-2DE2-4E84-BDE4-CD6CFB7EA952}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {585B9709-C7AB-4079-A782-BF1F9A2EFDCF}
+	EndGlobalSection
+EndGlobal

+ 3 - 1
iZpl/build.gradle

@@ -4,6 +4,7 @@ evaluationDependsOn(':iZplPlugins:Editor')
 evaluationDependsOn(':iZplPlugins:rtsslink')
 evaluationDependsOn(':iZplPlugins:JukeBox')
 evaluationDependsOn(':iZplPlugins:Extractor')
+evaluationDependsOn(':iZplPlugins:discordjukebox')
 defaultTasks 'distZip'
 
 apply plugin: 'java'
@@ -100,6 +101,7 @@ distZip {
         from project(':iZplPlugins:rtsslink').jar
 		from project(':iZplPlugins:JukeBox').jar
         from project(':iZplPlugins:Extractor').jar
+        from project(':iZplPlugins:discordjukebox').jar
   }
 }
 
@@ -126,7 +128,7 @@ dependencies{
     compile 'org.apache.commons:commons-exec:1.3'
     compile "org.yaml:snakeyaml:1.14"
     compile "commons-net:commons-net:3.3"
-    compile 'uk.co.caprica:vlcj:+'
+    compile 'uk.co.caprica:vlcj:4+'
     compile 'com.googlecode.mp4parser:isoparser:1.0-RC-1'
     compile 'net.java.truevfs:truevfs-profile-default_2.11:0.12.0'
     compile 'commons-cli:commons-cli:1.3'

BIN
iZpl/lib/jar-loader.jar


BIN
iZpl/lib/jnafilechooser-api-0.1-SNAPSHOT.jar


BIN
iZpl/lib/jnafilechooser-win32-0.1-SNAPSHOT.jar


+ 1 - 1
iZpl/src/main/java/de/nplusc/izc/iZpl/API/IZPLApi.java

@@ -202,7 +202,7 @@ public class IZPLApi
      * SHorthand to allow checking if command line is attached
      * @return true if theres a console/commandline attached
      */
-    public boolean isCommandLined()
+    public static boolean isCommandLined()
     {
         return System.console()!=null;
     }

+ 15 - 1
iZpl/src/main/java/de/nplusc/izc/iZpl/API/PlayListEditAPI.java

@@ -11,6 +11,7 @@ import de.nplusc.izc.iZpl.API.shared.MultiPlayListItem;
 import de.nplusc.izc.iZpl.Main;
 import de.nplusc.izc.iZpl.PLServer;
 import de.nplusc.izc.iZpl.PlProcessorV2;
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -196,7 +197,7 @@ public class PlayListEditAPI
             String t = ((SinglePlayListItem) x).getTitle();
             if(t!=null && !t.equals(""))
             {
-                return t.split(",")[1];
+                return t.split(",",2)[1];
             }
             else
             {
@@ -230,6 +231,19 @@ public class PlayListEditAPI
         return x.getTargetPlaycount();
     }
     
+    /**
+     * Obtains the filesize of the track with the given ID
+     * @param id Position in the track list obtained with getTrackTitles()
+     * @return Filesize
+     */
+    public static long getTargetFileSize(int id)
+    {
+        String k=playListItemKeys.get(id);
+        PlayListItem x =Main.getPLServer().getPlProcessorV2().getPool().get(k);
+        File f = new File(x.getPath());
+        return f.length();
+    }
+    
     /**
      * Sets the target playcount for the given title
      * @param id Position in the track list obtained with getTrackTitles()

+ 47 - 43
iZpl/src/main/java/de/nplusc/izc/iZpl/API/Plugin.java

@@ -1,43 +1,47 @@
-/*
- * Copyright (C) 2015 iZc
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package de.nplusc.izc.iZpl.API;
-
-/**
- * Minimal Methods required by any plugin
- * @author iZc <nplusc.de>
- */
-public interface Plugin
-{
-    /**
-     * Defines the name of the Plugin used in the Configuration Screen
-     * @return Plugin name which should be unique
-     */
-    public String getPluginName();
-    /**
-     * Initializes the core parts of the plugin. 
-     * Called after the configuration file got loaded but before the mode of the program got determined
-     */
-    public void initializePlugin();
-    
-    /**
-     * gets called when the upgrade parameter is set on the commandline. called before PluginInit
-     */
-    public void prepareUpgrade();
-            
-    
-}
+/*
+ * Copyright (C) 2015 iZc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.nplusc.izc.iZpl.API;
+
+/**
+ * Minimal Methods required by any plugin
+ * @author iZc <nplusc.de>
+ */
+public interface Plugin
+{
+    /**
+     * Defines the name of the Plugin used in the Configuration Screen
+     * @return Plugin name which should be unique
+     */
+    public String getPluginName();
+    /**
+     * Initializes the core parts of the plugin. 
+     * Called after the configuration file got loaded but before the mode of the program got determined
+     */
+    public void initializePlugin();
+    
+    /**
+     * gets called when the upgrade parameter is set on the commandline. called before PluginInit
+     */
+    public void prepareUpgrade();
+            
+    /**
+     * Optional Hook for loading a config file 
+     */
+    public default void loadConfig(){};
+    
+}

+ 14 - 7
iZpl/src/main/java/de/nplusc/izc/iZpl/API/PluginManager.java

@@ -34,10 +34,8 @@ import java.lang.reflect.InvocationTargetException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
+
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.yaml.snakeyaml.Yaml;
@@ -187,7 +185,10 @@ public class PluginManager
             if (playbackPlugin.getPluginName().equals(Main.CONFIG.getMediaPlayerForStandalone()))
             {
                 if(firstrunmode||updateInit)
+                {
                     playbackPlugin.initializePlugin();
+                }
+                playbackPlugin.loadConfig();
                 selectedPlaybackPlugin = playbackPlugin;
             }
         }
@@ -200,6 +201,7 @@ public class PluginManager
                     uIPlugin.initializePlugin();
                     Main.updatePluginInitProgress(2, 1, uIPlugin.getPluginName());
                 }
+                uIPlugin.loadConfig();
                 selectedUIPlugin = uIPlugin;
             }
         }
@@ -215,6 +217,7 @@ public class PluginManager
                     featurePlugin.initializePlugin();
                     Main.updatePluginInitProgress(2, 2, featurePlugin.getPluginName());
                 }
+                featurePlugin.loadConfig();
             }
         }
         if(featurePluginMode&&selectedFeaturePlugin==null)
@@ -302,10 +305,14 @@ public class PluginManager
                     List<String> supportedArchs = (List<String>) plugindata.get("supportedarchitectures");
                     if (supportedOSes.contains(osdata[0]) && supportedArchs.contains(osdata[1]))
                     {
-                        Class clazz = new URLClassLoader(new URL[]
+                        ca.cgjennings.jvm.JarLoader.addToClassPath(new File(plugin));
+
+
+                        Class clazz = Class.forName((String) plugindata.get("pluginbaseclass"));
+                                /*new URLClassLoader(new URL[]
                         {
-                            new File(plugin).toURI().toURL()
-                        }).loadClass((String) plugindata.get("pluginbaseclass"));
+                                new File(plugin).toURI().toURL()
+                        }).loadClass();*/
                         // holen der Interfaces die die Klasse impementiert
                         Class[] interfaces = clazz.getInterfaces();
                         // Durchlaufen durch die Interfaces der Klasse und nachsehn ob es das passende Plugin implementiert

+ 1 - 0
iZplPlugins/discordjukebox/.gitignore

@@ -0,0 +1 @@
+auxy

+ 19 - 0
iZplPlugins/discordjukebox/build.gradle

@@ -0,0 +1,19 @@
+apply plugin:'java'
+task distZip(dependsOn: 'jar') {
+	//NO-OPtask als redirect
+}
+
+
+
+
+
+compileJava.options.encoding = 'UTF-8'
+dependencies
+{
+	compile fileTree(dir: 'lib', include: '*.jar')
+	compile project(':iZpl')
+   
+
+}
+
+

+ 60 - 0
iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/Configuration.java

@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 iZc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package de.nplusc.izc.izpl.plugins.discord;
+
+/**
+ *
+ * @author iZc <nplusc.de>
+ */
+public class Configuration
+{
+    private String outputFolder;
+    private String baseUrl;
+    private String DiscordToken;
+
+    public String getOutputFolder()
+    {
+        return outputFolder;
+    }
+
+    public void setOutputFolder(String outputFolder)
+    {
+        this.outputFolder = outputFolder;
+    }
+
+    public String getBaseUrl()
+    {
+        return baseUrl;
+    }
+
+    public void setBaseUrl(String baseUrl)
+    {
+        this.baseUrl = baseUrl;
+    }
+
+    public String getDiscordToken()
+    {
+        return DiscordToken;
+    }
+
+    public void setDiscordToken(String DiscordToken)
+    {
+        this.DiscordToken = DiscordToken;
+    }
+    
+    
+}

+ 220 - 0
iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/Discord.java

@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2017 iZc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package de.nplusc.izc.izpl.plugins.discord;
+
+import com.sun.jna.Native;
+import com.sun.jna.NativeLibrary;
+import de.nplusc.izc.iZpl.API.FeaturePlugin;
+import de.nplusc.izc.iZpl.API.IZPLApi;
+import de.nplusc.izc.iZpl.API.PlaybackStatusPlugin;
+import de.nplusc.izc.iZpl.API.PluginManager;
+import de.nplusc.izc.iZpl.API.UIPlugin;
+import de.nplusc.izc.tools.UiToolz.UiTools;
+import de.nplusc.izc.tools.baseTools.Detectors;
+import de.nplusc.izc.tools.baseTools.OutputStreamBridge;
+import de.nplusc.izc.tools.baseTools.Tools;
+import net.java.truevfs.access.TFile;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import javax.swing.JTextArea;
+import org.apache.commons.io.output.NullOutputStream;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ *
+ * @author iZc <nplusc.de>
+ */
+public class Discord implements FeaturePlugin
+{
+    private static final Logger l = LogManager.getLogger();
+    private static String jarschiv = Discord.class.getProtectionDomain().getCodeSource().getLocation().getPath();
+    
+    private static Configuration config = null;
+    
+    private static final String CONFIGPATH = IZPLApi.PLUGINPATH+File.separator+"DiscordJukebox"+File.separator+"config.yml";
+    
+    /**
+     * used as a pepper for the hashed URL on the server storage
+     */
+    static final String PREFIX="äiewpqf<qpöfdj+  fdwFOAWE<fÜ*WFAE<IFAWEF<AWF";
+    
+    
+    @Override
+    public String getPluginName()
+    {
+        return "IZPL->Discord integration";
+    }
+
+    @Override
+    public void initializePlugin()
+    {
+        l.info("extracting DiscordJukebox natives");
+        String[] osmetadata = Detectors.getSystemClassification();
+        l.info("Os-data:"+Arrays.toString(osmetadata));
+        if (osmetadata[0].equals("windows"))
+        {
+            
+            File target = new File(IZPLApi.PLUGINPATH+File.separator+"DiscordJukebox"
+                    +File.separator+"binaries"+File.separator+"ffmpeg.exe");
+            target.getParentFile().mkdirs();
+            if (!target.exists())
+            {
+                TFile zippo = new TFile(jarschiv + "\\binaries\\"+osmetadata[0]+"\\ffmpeg.exe");
+                try
+                {
+                    zippo.cp(target);
+                    TFile jarschcrap = new TFile(jarschiv + "\\binaries\\");
+                    jarschcrap.rm_r();//removal of the embedded FFMPEG binary after init
+                }
+                catch (IOException ex)
+                {
+                    
+                    ex.printStackTrace();
+                }
+
+            }
+        }
+        else
+        {
+            //TODO add check for ffmpeg on PATH for MacOS and Linux
+            throw new UnsupportedOperationException("ERROR! Not yet implemented.");
+        }
+    }
+
+    @Override
+    public void loadConfig()
+    {
+        File configFile = new TFile(CONFIGPATH);
+        if(configFile.exists())
+        {
+            try
+            {
+                Yaml y = new Yaml();
+                config = (Configuration) (y.loadAs(new FileInputStream(configFile),Configuration.class));
+            }
+            catch (FileNotFoundException ex)
+            {
+                ex.printStackTrace();
+            }
+        }
+        else
+        {
+            config = new Configuration();
+            config.setBaseUrl("");
+            config.setDiscordToken("");
+            config.setOutputFolder("");
+        }
+        saveConfig();
+        
+    }
+    
+    public void saveConfig()
+    {
+        File configFile = new TFile(CONFIGPATH);
+        try
+        {
+            new Yaml().dump(config, new FileWriter(configFile));
+        }
+        catch (IOException ex)
+        {
+            ex.printStackTrace();
+        }
+    }
+    
+    @Override
+    public void prepareUpgrade()
+    {
+        if(new TFile(jarschiv + "\\binaries").exists()) //nullroute falls reinit nicht möglich da files schon ausgepackt wurden
+        {
+            try
+            {
+                //killen der alten vlc-natives
+                TFile f =  new TFile(IZPLApi.PLUGINPATH+File.separator+"DiscordJukebox"+File.separator+"binaries");
+                if(f.exists())
+                    f.rm_r();
+            }
+            catch (IOException ex)
+            {
+                ex.printStackTrace();
+            }
+        }
+        else
+        {
+            l.warn("");
+        }
+    }
+
+    @Override
+    public void parseParameter(String param) {
+        if(config.getDiscordToken().length()==0&&IZPLApi.isCommandLined())
+        {
+            l.error("API Key Required for logging in");
+            IZPLApi.quickQuitWithoutSaving();
+        }
+        else
+        {   if(config.getDiscordToken().length()==0)
+            {
+                config.setDiscordToken(Tools.getInputString("Enter the Discord Token for your bot account"));
+                saveConfig();
+            }
+        }
+        java.awt.EventQueue.invokeLater(()->
+            new UI(this).setVisible(true)
+        );
+    }
+
+    @Override
+    public boolean hasUserInterface() {
+        return true;
+    }
+
+    @Override
+    public void openUserInterface() {
+
+    }
+
+    @Override
+    public boolean requiresLoadedPlayList() {
+        return true;
+    }
+    
+    static String hashFilename(long size, String filename)
+    {
+        String input = size+"|"+PREFIX+"|"+filename;
+        MessageDigest md = null;
+        try {
+            md = MessageDigest.getInstance("SHA-1");
+        }
+        catch(NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            return "ERROR---"+input.hashCode();
+        }
+        md.update(input.getBytes(Charset.defaultCharset()));
+        return String.format("%040x", new BigInteger(1, md.digest()));
+    }
+}

+ 109 - 0
iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/JukeBox.form

@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="3"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="tablePane" alignment="0" pref="468" max="32767" attributes="0"/>
+                  <Component id="btnEnqueue" alignment="1" max="32767" attributes="0"/>
+                  <Component id="btnRandom" alignment="0" max="32767" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="tablePane" min="-2" pref="698" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="btnRandom" pref="37" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="btnEnqueue" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="tablePane">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JTable" name="tblPLE">
+          <Properties>
+            <Property name="autoCreateRowSorter" type="boolean" value="true"/>
+            <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor" postCode="tblPLE.setColumnModel (new HidableTableColumnModel(tblPLE.getColumnModel()));">
+              <Table columnCount="2" rowCount="4">
+                <Column editable="false" title="ID" type="java.lang.Object"/>
+                <Column editable="false" title="Title" type="java.lang.Object"/>
+              </Table>
+            </Property>
+            <Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
+              <TableColumnModel selectionModel="0">
+                <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
+                  <Title/>
+                  <Editor/>
+                  <Renderer/>
+                </Column>
+                <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true">
+                  <Title/>
+                  <Editor/>
+                  <Renderer/>
+                </Column>
+              </TableColumnModel>
+            </Property>
+            <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
+              <TableHeader reorderingAllowed="false" resizingAllowed="true"/>
+            </Property>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JButton" name="btnEnqueue">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+          <Font name="Tahoma" size="20" style="0"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Einreihen"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnEnqueueActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="btnRandom">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Ausw&#xfc;rfeln"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRandomActionPerformed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>

+ 264 - 0
iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/JukeBox.java

@@ -0,0 +1,264 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package de.nplusc.izc.izpl.plugins.discord;
+
+import de.nplusc.izc.iZpl.API.IZPLApi;
+import de.nplusc.izc.iZpl.API.PlayListEditAPI;
+import de.nplusc.izc.iZpl.API.shared.InvalidPlayListFileException;
+import de.nplusc.izc.tools.baseTools.Detectors;
+import de.nplusc.izc.tools.baseTools.HidableTableColumnModel;
+import java.awt.Dimension;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.table.DefaultTableModel;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ *
+ * @author tgoerner
+ */
+public class JukeBox extends javax.swing.JFrame
+{
+    public static final int JUKEBOX_PORT=0x6767;
+    private static final Logger l = LogManager.getLogger();
+    /**
+     * Creates new form JukeBoxGUI
+     */
+    public JukeBox()
+    {
+    }
+    
+    
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents()
+    {
+
+        tablePane = new javax.swing.JScrollPane();
+        tblPLE = new javax.swing.JTable();
+        btnEnqueue = new javax.swing.JButton();
+        btnRandom = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+
+        tblPLE.setAutoCreateRowSorter(true);
+        tblPLE.setModel(new javax.swing.table.DefaultTableModel(
+            new Object [][]
+            {
+                {null, null},
+                {null, null},
+                {null, null},
+                {null, null}
+            },
+            new String []
+            {
+                "ID", "Title"
+            }
+        )
+        {
+            boolean[] canEdit = new boolean []
+            {
+                false, false
+            };
+
+            public boolean isCellEditable(int rowIndex, int columnIndex)
+            {
+                return canEdit [columnIndex];
+            }
+        });
+        tblPLE.setColumnModel (new HidableTableColumnModel(tblPLE.getColumnModel()));
+        tblPLE.getTableHeader().setReorderingAllowed(false);
+        tablePane.setViewportView(tblPLE);
+
+        btnEnqueue.setFont(new java.awt.Font("Tahoma", 0, 20)); // NOI18N
+        btnEnqueue.setText("Einreihen");
+        btnEnqueue.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                btnEnqueueActionPerformed(evt);
+            }
+        });
+
+        btnRandom.setText("Auswürfeln");
+        btnRandom.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                btnRandomActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(tablePane, javax.swing.GroupLayout.DEFAULT_SIZE, 468, Short.MAX_VALUE)
+                    .addComponent(btnEnqueue, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addComponent(btnRandom, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(tablePane, javax.swing.GroupLayout.PREFERRED_SIZE, 698, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(btnRandom, javax.swing.GroupLayout.DEFAULT_SIZE, 37, Short.MAX_VALUE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(btnEnqueue)
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void btnEnqueueActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_btnEnqueueActionPerformed
+    {//GEN-HEADEREND:event_btnEnqueueActionPerformed
+        int viewRow = tblPLE.getSelectedRow();
+        viewRow = tblPLE.convertRowIndexToModel(viewRow);
+        int index = (Integer)((DefaultTableModel)tblPLE.getModel()).getValueAt(viewRow,0);
+        if(index>=0)
+        {
+            // XXX Send 2 Discord
+        }
+    }//GEN-LAST:event_btnEnqueueActionPerformed
+
+    private void btnRandomActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_btnRandomActionPerformed
+    {//GEN-HEADEREND:event_btnRandomActionPerformed
+        // TODO add your handling code here:
+    }//GEN-LAST:event_btnRandomActionPerformed
+
+    private void rebuildTable(boolean recovery)
+    {
+        try
+        {
+            //mdl.setAllColumnsVisible();
+            
+            PlayListEditAPI.refreshKeyList();
+            String[] titles = PlayListEditAPI.getTrackTitles();
+            
+            DefaultTableModel mdl = ((DefaultTableModel)tblPLE.getModel());
+            mdl.setRowCount(titles.length>0?titles.length:1);
+            if(titles.length>0)
+            {
+                mdl.setValueAt(0,0,0);
+                mdl.setValueAt(titles[0],0,1);
+            }
+            else
+            {
+                mdl.setValueAt(-1,0,0);
+                mdl.setValueAt("-- NO TRACKS --",0,1);
+            }
+            for (int i = 0; i < titles.length; i++)
+            {
+                mdl.setValueAt(i,i,0);
+                mdl.setValueAt(titles[i],i,1);
+            }
+            
+            //HACK!
+            tblPLE.getRowSorter().toggleSortOrder(1);
+            tblPLE.getRowSorter().toggleSortOrder(1);
+        }
+        catch(InvalidPlayListFileException e)
+        {
+            if(recovery)
+            {
+                l.error("Serious statefile corruption detected");
+                IZPLApi.quickQuitWithoutSaving();//this should not happen at all on remote
+            }
+            //reloading data from disk and flushing internal references when the resume state got corrupted from a encoding change
+            PlayListEditAPI.reloadList();
+            rebuildTable(recovery);
+        }
+        //mdl.setColumnVisible(0, false);
+    }
+    
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton btnEnqueue;
+    private javax.swing.JButton btnRandom;
+    private javax.swing.JScrollPane tablePane;
+    private javax.swing.JTable tblPLE;
+    // End of variables declaration//GEN-END:variables
+
+       
+    private HidableTableColumnModel mdl = null;
+    
+    
+    public void initializeUI()
+    {
+        boolean onARM = Detectors.getSystemClassification()[1].equals("arm");
+        if(onARM)
+        {
+            setUndecorated(true);
+            setLocation(0, 0);
+        }
+        setIconImage(IZPLApi.getProgramIcon());
+        initComponents();
+        JLabel tmp = new JLabel("  "); //HACK incoming
+        tmp.setMinimumSize(new Dimension(30, 30));
+        tmp.setMaximumSize(new Dimension(30, 30));
+        tmp.setPreferredSize(new Dimension(30, 30));
+        tablePane.setCorner(ScrollPaneConstants.LOWER_RIGHT_CORNER, tmp);
+        tablePane.getVerticalScrollBar().setPreferredSize(
+            new Dimension(30, Integer.MAX_VALUE));
+        this.pack();
+        
+        //END HACK
+        mdl=(HidableTableColumnModel) tblPLE.getColumnModel();
+        mdl.setColumnVisible(mdl.getColumn(0), false);
+        addWindowListener(new WindowAdapter()
+        {
+            @Override
+            public void windowClosing(WindowEvent e)
+            {
+                //TODO
+            }
+        });
+        
+
+        
+        //play();
+        int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
+        
+        /*
+        InputMap inputMap = getRootPane().getInputMap(condition);
+        ActionMap actionMap = getRootPane().getActionMap();
+        KeyStroke spacebar = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE , 0, false);
+        String leertaste = "leertaste gedappt";
+        inputMap.put( spacebar,leertaste);
+        actionMap.put(leertaste, new AbstractAction()
+        {
+
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+                play();
+            }
+        });
+        */
+        
+        // selectedPlaybackPlugin.registerVideoSurface(videoPanel);
+        //TODO: HAX für RPi mit ProjectM-SDL/PulseAudio fullscreen. 
+        // HW-Incompat, Requires different HW
+        //TODO jukeboxBackend.reload();
+        tblPLE.getRowSorter().toggleSortOrder(1);
+        rebuildTable(false);
+        
+    }
+}

+ 117 - 0
iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/UI.form

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="3"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="gotoPlaybackView" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
+          </Group>
+          <Group type="102" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="baseUrl" max="32767" attributes="0"/>
+                  <Group type="102" attributes="0">
+                      <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                          <Component id="btnConvert" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel2" alignment="0" min="-2" pref="77" max="-2" attributes="0"/>
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="outputFolder" min="-2" pref="268" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="btnChoosePath" min="-2" pref="106" max="-2" attributes="0"/>
+                          </Group>
+                          <Component id="progressConvert" alignment="0" max="32767" attributes="0"/>
+                      </Group>
+                      <EmptySpace min="0" pref="8" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
+              <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="baseUrl" min="-2" max="-2" attributes="0"/>
+              <EmptySpace pref="47" max="32767" attributes="0"/>
+              <Component id="gotoPlaybackView" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="separate" max="-2" attributes="0"/>
+              <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="outputFolder" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="btnChoosePath" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="btnConvert" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="progressConvert" min="-2" pref="34" max="-2" attributes="0"/>
+              <EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JButton" name="btnConvert">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Convert for upload"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnConvertActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="gotoPlaybackView">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Playback!"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="baseUrl">
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Base URL"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="outputFolder">
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Output folder"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JButton" name="btnChoosePath">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Choose"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnChoosePathActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JProgressBar" name="progressConvert">
+    </Component>
+  </SubComponents>
+</Form>

+ 269 - 0
iZplPlugins/discordjukebox/src/main/java/de/nplusc/izc/izpl/plugins/discord/UI.java

@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2021 iZc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package de.nplusc.izc.izpl.plugins.discord;
+
+import de.nplusc.izc.iZpl.API.IZPLApi;
+import de.nplusc.izc.iZpl.API.PlayListEditAPI;
+import de.nplusc.izc.iZpl.API.shared.InvalidPlayListFileException;
+import de.nplusc.izc.iZpl.API.shared.PlayListItem;
+import de.nplusc.izc.iZpl.Utils.shared.PLFileIO;
+import de.nplusc.izc.tools.IOtools.FileTK;
+import de.nplusc.izc.tools.baseTools.Tools;
+import java.awt.EventQueue;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import jnafilechooser.api.JnaFileChooser;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.io.IoBuilder;
+
+/**
+ *
+ * @author iZc <nplusc.de>
+ */
+public class UI extends javax.swing.JFrame
+{
+    private static final Logger l = LogManager.getLogger();
+    
+    private int filesDone = 0;
+    
+    private Discord discord;
+    
+    /**
+     * Creates new form UI
+     */
+    public UI(Discord instance)
+    {
+        discord = instance;
+        initComponents();
+    }
+
+    /**
+     * This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents()
+    {
+
+        btnConvert = new javax.swing.JButton();
+        gotoPlaybackView = new javax.swing.JButton();
+        baseUrl = new javax.swing.JTextField();
+        jLabel1 = new javax.swing.JLabel();
+        outputFolder = new javax.swing.JTextField();
+        jLabel2 = new javax.swing.JLabel();
+        btnChoosePath = new javax.swing.JButton();
+        progressConvert = new javax.swing.JProgressBar();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+
+        btnConvert.setText("Convert for upload");
+        btnConvert.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                btnConvertActionPerformed(evt);
+            }
+        });
+
+        gotoPlaybackView.setText("Playback!");
+
+        jLabel1.setText("Base URL");
+
+        jLabel2.setText("Output folder");
+
+        btnChoosePath.setText("Choose");
+        btnChoosePath.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                btnChoosePathActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(gotoPlaybackView)
+                .addGap(0, 0, Short.MAX_VALUE))
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(baseUrl)
+                    .addGroup(layout.createSequentialGroup()
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                            .addComponent(btnConvert)
+                            .addComponent(jLabel1)
+                            .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE)
+                            .addGroup(layout.createSequentialGroup()
+                                .addComponent(outputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 268, javax.swing.GroupLayout.PREFERRED_SIZE)
+                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                                .addComponent(btnChoosePath, javax.swing.GroupLayout.PREFERRED_SIZE, 106, javax.swing.GroupLayout.PREFERRED_SIZE))
+                            .addComponent(progressConvert, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                        .addGap(0, 8, Short.MAX_VALUE)))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addGap(18, 18, 18)
+                .addComponent(jLabel1)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(baseUrl, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 47, Short.MAX_VALUE)
+                .addComponent(gotoPlaybackView)
+                .addGap(18, 18, 18)
+                .addComponent(jLabel2)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(outputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(btnChoosePath))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(btnConvert)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(progressConvert, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addGap(14, 14, 14))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void btnChoosePathActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_btnChoosePathActionPerformed
+    {//GEN-HEADEREND:event_btnChoosePathActionPerformed
+
+        JnaFileChooser fc = new JnaFileChooser();
+        fc.setMode(JnaFileChooser.Mode.Directories);
+        if (fc.showOpenDialog(this)) {
+            File f = fc.getSelectedFile();
+            outputFolder.setText(f.getPath());
+        }    
+    }//GEN-LAST:event_btnChoosePathActionPerformed
+
+    private void btnConvertActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_btnConvertActionPerformed
+    {//GEN-HEADEREND:event_btnConvertActionPerformed
+        new Thread(()->
+        {
+            String outputPath = outputFolder.getText();
+            if(!outputPath.isEmpty())
+            {
+                FileTK.ensuredirExistence(outputPath+"\\x");
+                String izpl = PlayListEditAPI.getCurrentPlaylist();
+                try
+                {
+                    List<PlayListItem> files = PLFileIO.parseFullList(izpl);
+                    final List<String[]> commands = new ArrayList<>();
+                    files.forEach(itm->
+                    {
+                        long size = new File(itm.getPath()).length();
+                        if(size>0)
+                        {
+                            String targetfilename = PlayListEditAPI.getTitle(itm);
+                            String folderHash = discord.hashFilename(size, targetfilename);
+                            String resultFile = outputPath+"\\"+folderHash+"\\"+targetfilename+".mp3";
+                            FileTK.ensuredirExistence(resultFile);
+                            String[] cmd = 
+                            {
+                                IZPLApi.PLUGINPATH+File.separator+"DiscordJukebox"+File.separator+"binaries"+File.separator+"ffmpeg.exe",
+                            "-i",
+                            itm.getPath(),
+                            "-vn",
+                            "-ar",
+                            "44100",
+                            "-ac",
+                            "2",
+                            "-b:a",
+                            "192k",
+                            resultFile
+                            };
+                            commands.add(cmd);
+                            // ffmpeg -i input.wav -vn -ar 44100 -ac 2 -b:a 192k output.mp3
+                        }
+                    });
+                    Queue<String[]> commandsToRun = new ConcurrentLinkedQueue<String[]>(commands);
+
+
+                    progressConvert.setMaximum(commands.size());
+                    progressConvert.setValue(0);
+                    Runnable r = ()->
+                            {
+                                String[] cmd = commandsToRun.poll();
+                                while(cmd!=null)
+                                {
+                                    Tools.runCmdWithPassthru(
+                                            IoBuilder.forLogger("External.FFMpeg").buildPrintStream(),
+                                            cmd);
+                                    synchronized(discord)
+                                    {
+                                        filesDone++;
+                                        EventQueue.invokeLater(()->
+                                        {
+                                            progressConvert.setValue(filesDone);
+                                        });
+                                    }
+                                    cmd = commandsToRun.poll();
+                                }
+                            };
+                    Thread[] processingthreads = new Thread[8];
+                    for(int i=0;i<8;i++)
+                    {
+                        Thread t = new Thread(r, "WPC-Worker-"+i);
+                        processingthreads[i] = t;
+                        t.start();
+                    }
+                    for(int i=0;i<8;i++)
+                    {
+                        try{
+                            processingthreads[i].join();
+                        }
+                        catch(InterruptedException e)
+                        {
+
+                        };
+                    }
+                        EventQueue.invokeLater(()->
+                        {
+                            progressConvert.setValue(filesDone);
+                        });
+                    l.info("Multithreaded processing finished");
+                }
+                catch (InvalidPlayListFileException ex)
+                {
+                    ex.printStackTrace();
+                }
+            }
+        }).start();
+    }//GEN-LAST:event_btnConvertActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JTextField baseUrl;
+    private javax.swing.JButton btnChoosePath;
+    private javax.swing.JButton btnConvert;
+    private javax.swing.JButton gotoPlaybackView;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JTextField outputFolder;
+    private javax.swing.JProgressBar progressConvert;
+    // End of variables declaration//GEN-END:variables
+}

BIN
iZplPlugins/discordjukebox/src/main/resources/binaries/windows/ffmpeg.exe


+ 11 - 0
iZplPlugins/discordjukebox/src/main/resources/plugin.yml

@@ -0,0 +1,11 @@
+pluginbaseclass: de.nplusc.izc.izpl.plugins.discord.Discord
+supportedoses:
+  - 'windows'
+  - 'mac'
+  - 'linux'
+# can be windows, mac or linux
+supportedarchitectures:
+  - 'x86'
+  - 'x64'
+  - 'arm'
+# x86 or x64 valid

+ 239 - 235
izpl-shared/src/main/java/de/nplusc/izc/iZpl/API/shared/MultiPlayListItem.java

@@ -1,235 +1,239 @@
-/*
- * Copyright (C) 2015 iZc
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package de.nplusc.izc.iZpl.API.shared;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-/**
- *
- * @author LH
- */
-public class MultiPlayListItem implements PlayListItem
-{
-    
-    private String[] prefix;
-    private String[] innerComments;
-    
-    private List<PlayListItem> containedElements=new ArrayList<>();
-    
-    private int playcount,countPlayed;
-    private String src="";
-    
-    public MultiPlayListItem(){};
-    
-    
-    public MultiPlayListItem(String[] path, String[] Title, int playcount)
-    {
-        for (int i = 0; i < Title.length; i++)
-        {
-            String t = Title[i];
-            String p = path[i];
-            containedElements.add(new SinglePlayListItem(p, t, 1));
-        }
-        this.playcount = playcount;
-        countPlayed=0; //noch nie gespielt als default; bei reload wird anderweitig verglichen :P
-    }
-
-    public List<PlayListItem> getItems()
-    {
-        return containedElements;
-    }
-    
-    public void setItems(List<PlayListItem>p)
-    {
-        containedElements=p;
-    }
-
-    public void addItem(PlayListItem e)
-    {
-        containedElements.add(e);
-    }
-    
-    public void removeElement(int i)
-    {
-        containedElements.remove(i);
-    }
-    
-    
-    public String getPath(int i)
-    {
-        PlayListItem it = containedElements.get(i);
-        if(it instanceof SinglePlayListItem)
-        {
-            return ((SinglePlayListItem)it).getPath();
-        }
-        return "";
-    }
-
-    
-    public int getElemCount()
-    {
-        return containedElements.size();
-    }
-   /* public void setPath(String path, int i)
-    {
-        this.
-        this.path.add(i, path);
-    }*/
-
-    public String getTitle(int i)
-    {
-        PlayListItem it = containedElements.get(i);
-        if(it instanceof SinglePlayListItem)
-        {
-            return ((SinglePlayListItem)it).getTitle();
-        }
-        return "";
-    }
-        
-    
-    public void addTitle(String ppath,String ptitle)
-    {
-        containedElements.add(new SinglePlayListItem(ppath, ptitle, 1));
-    }
-
-    @Override
-    public int getTargetPlaycount()
-    {
-        return playcount;
-    }
-
-    @Override
-    public void setTargetPlaycount(int playcount)
-    {
-        this.playcount = playcount;
-    }
-
-    @Override
-    public int getCountPlayed()
-    {
-        return countPlayed;
-    }
-
-    @Override
-    public void setCountPlayed(int countPlayed)
-    {
-        this.countPlayed = countPlayed;
-    }
-    
-    @Override
-    public String getM3UElement()
-    {
-        String sret = "";
-        for (PlayListItem playListItem : containedElements)
-        {
-            sret+=playListItem.getM3UElement();
-        }
-        return sret;
-    }
-
-
-    @Override
-    public int hashCode()
-    {
-        int hash = 7;
-        hash = 47 * hash + Objects.hashCode(containedElements);
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (obj == null)
-        {
-            return false;
-        }
-        if (getClass() != obj.getClass())
-        {
-            return false;
-        }
-        final MultiPlayListItem other = (MultiPlayListItem) obj;
-        if (!containedElements.equals(other.containedElements))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public String getSrc()
-    {
-        return src;
-    }
-
-    public void setSrc(String src)
-    {
-        this.src = src;
-    }
-
-    @Override
-    public boolean isIncludeElement()
-    {
-        return false;
-    }
-
-    @Override
-    public boolean noexpandoninclude()
-    {
-        return false;
-    }
-    
-    public SinglePlayListItem[] getSinglePlayListElements()
-    {
-        ArrayList<SinglePlayListItem> l = new ArrayList<>();
-        for (PlayListItem playListItem : containedElements)
-        {
-            if(playListItem instanceof SinglePlayListItem)
-            {
-                l.add((SinglePlayListItem) playListItem);
-            }
-            else
-            {
-                if(playListItem instanceof MultiPlayListItem)
-                {
-                    l.addAll(Arrays.asList(((MultiPlayListItem)playListItem).getSinglePlayListElements()));
-                }
-            }
-        }
-        return (SinglePlayListItem[]) l.toArray(new SinglePlayListItem[]{});
-    }
-
-    @Override
-    public int getGID()
-    {
-       return 0;
-    }
-
-    @Override
-    public String[] getPrefix()
-    {
-        return prefix;
-    }
-
-    @Override
-    public String[] getInnerCommentLines()
-    {
-        return innerComments;
-    }
-    
-}
+/*
+ * Copyright (C) 2015 iZc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package de.nplusc.izc.iZpl.API.shared;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ *
+ * @author LH
+ */
+public class MultiPlayListItem implements PlayListItem
+{
+    
+    private String[] prefix;
+    private String[] innerComments;
+    
+    private List<PlayListItem> containedElements=new ArrayList<>();
+    
+    private int playcount,countPlayed;
+    private String src="";
+    
+    public MultiPlayListItem(){};
+    
+    
+    public MultiPlayListItem(String[] path, String[] Title, int playcount)
+    {
+        for (int i = 0; i < Title.length; i++)
+        {
+            String t = Title[i];
+            String p = path[i];
+            containedElements.add(new SinglePlayListItem(p, t, 1));
+        }
+        this.playcount = playcount;
+        countPlayed=0; //noch nie gespielt als default; bei reload wird anderweitig verglichen :P
+    }
+
+    public List<PlayListItem> getItems()
+    {
+        return containedElements;
+    }
+    
+    public void setItems(List<PlayListItem>p)
+    {
+        containedElements=p;
+    }
+
+    public void addItem(PlayListItem e)
+    {
+        containedElements.add(e);
+    }
+    
+    public void removeElement(int i)
+    {
+        containedElements.remove(i);
+    }
+    
+    public String getPath()
+    {
+        return getPath(1);
+    }
+    
+    public String getPath(int i)
+    {
+        PlayListItem it = containedElements.get(i);
+        if(it instanceof SinglePlayListItem)
+        {
+            return ((SinglePlayListItem)it).getPath();
+        }
+        return "";
+    }
+
+    
+    public int getElemCount()
+    {
+        return containedElements.size();
+    }
+   /* public void setPath(String path, int i)
+    {
+        this.
+        this.path.add(i, path);
+    }*/
+
+    public String getTitle(int i)
+    {
+        PlayListItem it = containedElements.get(i);
+        if(it instanceof SinglePlayListItem)
+        {
+            return ((SinglePlayListItem)it).getTitle();
+        }
+        return "";
+    }
+        
+    
+    public void addTitle(String ppath,String ptitle)
+    {
+        containedElements.add(new SinglePlayListItem(ppath, ptitle, 1));
+    }
+
+    @Override
+    public int getTargetPlaycount()
+    {
+        return playcount;
+    }
+
+    @Override
+    public void setTargetPlaycount(int playcount)
+    {
+        this.playcount = playcount;
+    }
+
+    @Override
+    public int getCountPlayed()
+    {
+        return countPlayed;
+    }
+
+    @Override
+    public void setCountPlayed(int countPlayed)
+    {
+        this.countPlayed = countPlayed;
+    }
+    
+    @Override
+    public String getM3UElement()
+    {
+        String sret = "";
+        for (PlayListItem playListItem : containedElements)
+        {
+            sret+=playListItem.getM3UElement();
+        }
+        return sret;
+    }
+
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 7;
+        hash = 47 * hash + Objects.hashCode(containedElements);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        final MultiPlayListItem other = (MultiPlayListItem) obj;
+        if (!containedElements.equals(other.containedElements))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    public String getSrc()
+    {
+        return src;
+    }
+
+    public void setSrc(String src)
+    {
+        this.src = src;
+    }
+
+    @Override
+    public boolean isIncludeElement()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean noexpandoninclude()
+    {
+        return false;
+    }
+    
+    public SinglePlayListItem[] getSinglePlayListElements()
+    {
+        ArrayList<SinglePlayListItem> l = new ArrayList<>();
+        for (PlayListItem playListItem : containedElements)
+        {
+            if(playListItem instanceof SinglePlayListItem)
+            {
+                l.add((SinglePlayListItem) playListItem);
+            }
+            else
+            {
+                if(playListItem instanceof MultiPlayListItem)
+                {
+                    l.addAll(Arrays.asList(((MultiPlayListItem)playListItem).getSinglePlayListElements()));
+                }
+            }
+        }
+        return (SinglePlayListItem[]) l.toArray(new SinglePlayListItem[]{});
+    }
+
+    @Override
+    public int getGID()
+    {
+       return 0;
+    }
+
+    @Override
+    public String[] getPrefix()
+    {
+        return prefix;
+    }
+
+    @Override
+    public String[] getInnerCommentLines()
+    {
+        return innerComments;
+    }
+    
+}

+ 36 - 35
izpl-shared/src/main/java/de/nplusc/izc/iZpl/API/shared/PlayListItem.java

@@ -1,35 +1,36 @@
-/*
- * Copyright (C) 2015 iZc
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package de.nplusc.izc.iZpl.API.shared;
-
-/**
- *
- * @author LH
- */
-public interface PlayListItem
-{
-    public String getM3UElement();// erzeugt den M3U-Code zum aujsgeben an den VauEllCeh-er
-    public int getTargetPlaycount(); 
-    public void setTargetPlaycount(int playcount);
-    public int getCountPlayed();
-    public void setCountPlayed(int countPlayed);
-    public boolean isIncludeElement(); //erweiterung um daten durchzuschleusen für die TreeView
-    public boolean noexpandoninclude();
-    public int getGID();
-    public String[] getPrefix();
-    public String[] getInnerCommentLines();
-}
+/*
+ * Copyright (C) 2015 iZc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package de.nplusc.izc.iZpl.API.shared;
+
+/**
+ *
+ * @author LH
+ */
+public interface PlayListItem
+{
+    public String getM3UElement();// erzeugt den M3U-Code zum aujsgeben an den VauEllCeh-er
+    public int getTargetPlaycount(); 
+    public void setTargetPlaycount(int playcount);
+    public int getCountPlayed();
+    public void setCountPlayed(int countPlayed);
+    public boolean isIncludeElement(); //erweiterung um daten durchzuschleusen für die TreeView
+    public boolean noexpandoninclude();
+    public int getGID();
+    public String getPath();
+    public String[] getPrefix();
+    public String[] getInnerCommentLines();
+}

+ 1 - 1
settings.gradle

@@ -1,4 +1,4 @@
 include 'ToolKit','iZpl',  'IZSetup','WPCMGr','UpidTK', 'izstreamer', 'LogBlockHeatMapper','iZlaunch',
 'iZpaqSFX','MazeViewer','TWPUtil',"iZplPlugins:WMP","iZplPlugins:foobar2000_others","iZplPlugins:itunes","iZplPlugins:GameRadio",
 "iZplPlugins:Editor","izpl-shared","iZpl-server","iZplPlugins:Smartphonizer","QuickStuff","external:java-progressbar","iZplPlugins:rtsslink","iZplPlugins:JukeBox",
-"iZplPlugins:Extractor","spungit_deathtimer"
+"iZplPlugins:Extractor","spungit_deathtimer","iZplPlugins:discordjukebox"

+ 0 - 29
spungit_deathtimer/build.gradle

@@ -1,29 +0,0 @@
-    plugins {
-       id 'kr.entree.spigradle' version '1.2.1' apply false
-    }
-
-apply plugin: 'java'
-if(org.gradle.api.JavaVersion.current().isJava11Compatible())
-{
-    apply plugin: 'kr.entree.spigradle'
-}
-else
-{
-   logger.warn('Full Build requires Java 11 or highher.')
-}
-group 'de.nplusc.izc'
-version '1.0-SNAPSHOT'
-
-sourceCompatibility = 1.8
-
-dependencies {
-  compileOnly 'org.spigotmc:spigot:1.15.2-R0.1-SNAPSHOT' // The full Spigot server with no shadowing. Requires mavenLocal.
-}
-if(org.gradle.api.JavaVersion.current().isJava11Compatible())
-{
-    spigot {
-       authors = ['iZc']
-       apiVersion = '1.15'
-       load = STARTUP
-    }
-}