Prechádzať zdrojové kódy

Merge branch 'master' of https://repo.nplusc.de/masterX244/iZinked

LH 4 mesiacov pred
rodič
commit
8844549e29
35 zmenil súbory, kde vykonal 1918 pridanie a 185 odobranie
  1. 25 0
      Megatron-Bridge/build.gradle
  2. 27 0
      Megatron-Bridge/build.gradle.bikini
  3. 239 0
      Megatron-Bridge/openapi.yaml
  4. 9 0
      Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/C3.java
  5. 9 0
      Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/CommandQueueItem.java
  6. 13 0
      Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/CommandType.java
  7. 38 0
      Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/MegatronBridgeApplication.java
  8. 115 0
      Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/MegatronController.java
  9. 175 0
      Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/MegatronService.java
  10. 28 0
      Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/Models/CustomAudio.java
  11. 11 0
      Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/Models/MovementActions.java
  12. 12 0
      Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/Models/OnboardAudio.java
  13. 27 0
      Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/Models/RawAction.java
  14. 296 0
      Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/SerialSpammer.java
  15. 1 0
      Megatron-Bridge/src/main/resources/application.properties
  16. 21 0
      Megatron-Bridge/src/main/resources/audiomapping.lst
  17. 143 0
      NETQuickies/SWR1HLSURLGen/Program.cs
  18. 8 0
      NETQuickies/SWR1HLSURLGen/SWR1HLSURLGen.csproj
  19. 25 0
      NETQuickies/SWR1HLSURLGen/SWR1HLSURLGen.sln
  20. 3 1
      QuickStuff/build.gradle
  21. 2 2
      QuickStuff/src/main/java/PV/UI.java
  22. 23 0
      QuickStuff/src/main/java/QuickVerifyCrap/ByteZilser.java
  23. 95 0
      QuickStuff/src/main/java/QuickVerifyCrap/CSVFlashMassageliege.java
  24. 10 7
      QuickStuff/src/main/java/QuickVerifyCrap/CSVMassageliege.java
  25. 67 0
      QuickStuff/src/main/java/QuickVerifyCrap/ChaosPostSpammer.java
  26. 188 0
      QuickStuff/src/main/java/QuickVerifyCrap/SerialSpammer.java
  27. 82 0
      QuickStuff/src/main/java/QuickVerifyCrap/WURestoreZuzel.java
  28. 16 0
      QuickStuff/src/main/java/QuickVerifyCrap/Zilsnerator.java
  29. 1 1
      SenaBitWiggler/src/main/java/de/nplusc/izc/senabitwiggler/FirmwareAutoDumper.java
  30. 2 2
      iZpl/src/main/java/de/nplusc/izc/iZpl/API/PlayListEditAPI.java
  31. 5 0
      iZplPlugins/Editor/src/main/java/de/nplusc/izc/izpl/plugins/editor/Editor.java
  32. 118 108
      izpl-shared/src/main/java/de/nplusc/izc/iZpl/API/shared/PlayListFile.java
  33. 70 59
      izpl-shared/src/main/java/de/nplusc/izc/iZpl/API/shared/RawPlayListFile.java
  34. 13 4
      izpl-shared/src/main/java/de/nplusc/izc/iZpl/Utils/shared/PLFileIO.java
  35. 1 1
      settings.gradle

+ 25 - 0
Megatron-Bridge/build.gradle

@@ -0,0 +1,25 @@
+plugins {
+	id 'java'
+	id 'org.springframework.boot' version '3.0+'
+	id 'io.spring.dependency-management' version '1.1.7'
+}
+
+group = 'de.nplusc.izc'
+version = '0.0.1-SNAPSHOT'
+
+//java {
+//	toolchain {
+//		languageVersion = JavaLanguageVersion.of(17)
+//	}
+//}
+sourceCompatibility = 1.17
+
+repositories {
+	mavenCentral()
+}
+
+dependencies {
+    implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0'
+	implementation 'org.springframework.boot:spring-boot-starter-web'
+	implementation 'com.fazecast:jSerialComm:[2.0.0,3.0.0)'
+}

+ 27 - 0
Megatron-Bridge/build.gradle.bikini

@@ -0,0 +1,27 @@
+defaultTasks 'distZip'
+
+apply plugin: 'java-library'
+apply plugin: 'application'
+
+
+sourceCompatibility = 1.17
+version = 'SNAPSHOT'
+mainClassName = 'de.nplusc.izc.MegatronBridge.C3'
+
+
+jar{
+	manifest{
+		attributes 'Implementation-Title': 'MegatronBridge',
+					'Implementation-Version': 'SNAPSHOT',
+					'Main-Class': 'de.nplusc.izc.MegatronBridge.C3'
+					
+	}
+}
+
+repositories{
+	mavenCentral()
+}
+
+dependencies{
+    implementation 'com.fazecast:jSerialComm:[2.0.0,3.0.0)'
+}

+ 239 - 0
Megatron-Bridge/openapi.yaml

@@ -0,0 +1,239 @@
+openapi: 3.0.3
+info:
+  title: Modgatron
+  description: |-
+    API to control the modded animatronic Megatron helmet from Killerbody over the LAN
+externalDocs:
+  description: TODO
+  url: https://nplusc.de
+servers:
+  - url: https://petstore3.swagger.io/api/v3
+paths:
+  /raw:
+    post:
+      summary: raw command posting
+      description: Debug command, don't bother to poke at it
+      operationId: flyswatter
+      requestBody:
+        description: raw cmd
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/RawCmd'
+          application/xml:
+            schema:
+              $ref: '#/components/schemas/RawCmd'
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: '#/components/schemas/RawCmd'
+        required: true
+      responses:
+        '200':
+          description: Successful operation
+        '400':
+          description: from \_\_future\_\_ import braces
+  /movement:
+    post:
+      summary: Trigger the animatronic parts
+      description: Triggers the animatronics 
+      operationId: wiggle
+      requestBody:
+        description: raw cmd
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Movement'
+          application/xml:
+            schema:
+              $ref: '#/components/schemas/Movement'
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: '#/components/schemas/Movement'
+        required: true
+      responses:
+        '200':
+          description: Successful operation
+        '400':
+          description: Bad data, operation not allowed
+############
+  /onboardAudio:
+    post:
+      summary: trigger default audio fragment
+      description: "plays one of the default audio fragments, WARNING: EXTREMELY LOUD"
+      operationId: onboard
+      requestBody:
+        description: raw cmd
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/onboardAudio'
+          application/xml:
+            schema:
+              $ref: '#/components/schemas/onboardAudio'
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: '#/components/schemas/onboardAudio'
+        required: true
+      responses:
+        '200':
+          description: Successful operation
+        '400':
+          description: Bad data, operation not allowed
+############
+  /customAudio:
+    post:
+      summary: Triggers custom preloaded audio fragment
+      description: Plays one of the custom preloaded audio fragments
+      operationId: custom
+      requestBody:
+        description: raw cmd
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/customAudio'
+          application/xml:
+            schema:
+              $ref: '#/components/schemas/customAudio'
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: '#/components/schemas/customAudio'
+        required: true
+      responses:
+        '200':
+          description: Successful operation
+        '400':
+          description: Bad data, operation not allowed
+############
+  /setVolume:
+    post:
+      summary: set volume level
+      description: set volume level from 0 (off) to 8
+      operationId: volume
+      requestBody:
+        description: raw cmd
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/VolumeLevel'
+          application/xml:
+            schema:
+              $ref: '#/components/schemas/VolumeLevel'
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: '#/components/schemas/VolumeLevel'
+        required: true
+      responses:
+        '200':
+          description: Successful operation
+        '400':
+          description: Bad data, operation not allowed
+  /dynamicAudio:
+    post:
+      summary: sends a audiofile to be played
+      description: sends a audio file which is converted and streamed over
+      operationId: stream
+      requestBody:
+        description: file to wiggle
+        content:
+          application/octet-stream:
+            schema:
+              type: string
+              format: binary
+        required: true
+      responses:
+        '200':
+          description: Successful operation
+        '400':
+          description: Bad data, operation not allowed
+############
+  /wiggleMouth:
+    post:
+      summary: Toggles the mouth wiggling
+      description: Toggles the mouth wiggling
+      operationId: bite
+      responses:
+        '200':
+          description: Successful operation
+components:
+  schemas:
+    VolumeLevel:
+      type: integer
+      format: int32
+      example: 8
+    RawCmd:
+      type: object
+      properties:
+        sequence:
+          type: string
+        psk:
+          type: string
+          description: authentication for this command, forget it......
+    customAudio:
+      type: object
+      properties:
+        sample:
+          type: string
+          description: modded audio snippets
+          enum:
+            - rogerroger
+            - r2d2-beepery
+            - jfo-_sfx_machinepowerup
+            - jfo-authenticated
+            - jfo-charged-and-ready
+            - jfo-core-programming-modified
+            - jfo-recalibrating
+            - jfo-scanning
+            - jfo-system_rebooted
+            - jfo-system-malfunction
+            - r2d2-demotivated
+            - gb-startup-sound
+            - worms_bittekommengrosservogel
+            - glados_ohdubistes
+            - glados-nicht-reinfallen
+            - glados-planb
+            - glados-seid-ihr-defekt
+            - hallelujah
+            - p2turret-fail
+            - worms_oede
+            - optimusprime
+        wiggle_mouth:
+          type: boolean
+      xml:
+        name: custom
+    onboardAudio:
+      type: string
+      description: original audio samples, WARNING EXTREMELY LOUD
+      enum:
+        - decepticonsretreat
+        - allhailmegatron
+        - bzzzzzzzrt
+        - decepticonsattack
+        - snd_eyelight_on
+        - snd_eyelight_off
+        - snd_bootup
+      xml:
+        name: onboard
+    Movement:
+      type: string
+      description: trigger moveable part
+      enum:
+        - eyeglow
+        - eyedark
+        - eyeflickering
+        - earwiggle
+        - battlemodeon
+        - battlemodeoff
+      xml:
+        name: movement
+    ApiResponse:
+      type: object
+      properties:
+        code:
+          type: integer
+          format: int32
+        type:
+          type: string
+        message:
+          type: string
+      xml:
+        name: '##default'

+ 9 - 0
Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/C3.java

@@ -0,0 +1,9 @@
+package de.nplusc.izc.MegatronBridge;
+
+public class C3
+{
+    public static void main(String[] args)
+    {
+
+    }
+}

+ 9 - 0
Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/CommandQueueItem.java

@@ -0,0 +1,9 @@
+package de.nplusc.izc.MegatronBridge;
+
+public class CommandQueueItem
+{
+    public CommandType type;
+    public int argument;
+    public String extendedArg;
+    public byte[] streamData;
+}

+ 13 - 0
Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/CommandType.java

@@ -0,0 +1,13 @@
+package de.nplusc.izc.MegatronBridge;
+
+//internal action types, not directly exposed publicly
+public enum CommandType
+{
+    ServoAction,
+    OnboardAudio,
+    CustomAudio,
+    StreamAudio,
+    MundwerkToggle,
+    VolumeSetter,
+    RawCommand
+}

+ 38 - 0
Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/MegatronBridgeApplication.java

@@ -0,0 +1,38 @@
+package de.nplusc.izc.MegatronBridge;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+
+@SpringBootApplication
+@EnableWebMvc
+public class MegatronBridgeApplication {
+
+	public static String PSK = "";
+	public static SerialSpammer spammer = null;
+	public static void main(String[] args)
+	{
+		if(args.length<2)
+		{
+			System.err.println("missing arguments, serial port and preshared key are both required");
+		}
+		spammer = new SerialSpammer(args[0]);
+		PSK=args[1];
+
+		SpringApplication.run(MegatronBridgeApplication.class, args);
+	}
+}
+@Configuration
+class OpenApiConfiguration implements WebMvcConfigurer
+{
+
+	@Override
+	public void addViewControllers(final ViewControllerRegistry registry) {
+		registry.addRedirectViewController("/", "swagger-ui/index.html");
+	}
+}
+

+ 115 - 0
Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/MegatronController.java

@@ -0,0 +1,115 @@
+package de.nplusc.izc.MegatronBridge;
+
+import de.nplusc.izc.MegatronBridge.Models.CustomAudio;
+import de.nplusc.izc.MegatronBridge.Models.MovementActions;
+import de.nplusc.izc.MegatronBridge.Models.OnboardAudio;
+import de.nplusc.izc.MegatronBridge.Models.RawAction;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+@RestController
+@Tag(name = "base", description = "API module for the Megatron sculpture at the CC86 assembly at 38C3")
+public class MegatronController
+{
+    @Autowired
+    private MegatronService svc;
+
+
+    @Operation(summary = "Sets the volume level, range is from 0 to 8", description = "Sets the volume for the custom audio to the given level")
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "successful operation"),
+            @ApiResponse(responseCode = "400", description = "Out of range value",content = @Content)}
+    )
+    @PostMapping("/volume")
+    @ResponseBody
+    public void setVolume(int volume)
+    {
+        svc.setVolume(volume);
+    }
+
+    @Operation(summary = "Raw lowlevel command, debugging only", description = "Raw command sending, don't waste your time if you don't have the secret key")
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "successful operation"),
+            @ApiResponse(responseCode = "401", description = "Not a chance!", content = @Content)}
+    )
+    @PostMapping("/debug")
+    @ResponseBody
+    public void executeRaw(RawAction action)
+    {
+        svc.executeRaw(action);
+    }
+
+    @Operation(summary = "Triggers one of the onboard audio snippets", description = "Plays one of the original builtin audio snippets, WARNING: LOUD!")
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "successful operation"),
+            @ApiResponse(responseCode = "400", description = "Out of range value", content = @Content)}
+    )
+    @PostMapping("/onboardAudio")
+    @ResponseBody
+    public void playOnbardAudio(OnboardAudio audio)
+    {
+        svc.playOnbardAudio(audio);
+    }
+
+    @Operation(summary = "Triggers one of the custom fixed audio snippets", description = "Plays one of the fixed custom audio snippets. Volume depends on configured volume")
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "successful operation"),
+            @ApiResponse(responseCode = "400", description = "Out of range value", content = @Content)}
+    )
+    @PostMapping("/customAudio")
+    @ResponseBody
+    public void playCustomAudio(CustomAudio audio)
+    {
+        svc.playCustomAudio(audio);
+    }
+    @Operation(summary = "Lists the valid custom audio snippets", description = "Lists the valid custom audio snippets")
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "successful operation")
+    })
+    @GetMapping("/customAudio")
+    public String[] listAudio()
+    {
+        return svc.listAudio();
+    }
+
+    @Operation(summary = "Triggers the fixed movement sequences", description = "Triggers one of the fixed movement actions")
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "successful operation"),
+            @ApiResponse(responseCode = "400", description = "Out of range value", content = @Content)}
+    )
+    @PostMapping("/wiggle")
+
+    public void wiggle(MovementActions action)
+    {
+        svc.wiggle(action);
+    }
+
+    @Operation(summary = "toggles mouth wiggling state", description = "Plays one of the original builtin audio snippets, WARNING: LOUD!")
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "successful operation"),
+            @ApiResponse(responseCode = "400", description = "Out of range value", content = @Content)}
+    )
+    @PostMapping("/wiggleMouth")
+    public void wiggleMouth()
+    {
+        svc.wiggleMouth();
+    }
+
+
+
+    @Operation(summary = "send raw audio to be played", description = "plays raw 11khz 8bit signed PCM audio (max 60seconds)")
+    @PostMapping(value = "dynamicAudio",
+            consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public void streamAudio(@RequestParam("file") MultipartFile file)
+    {
+        svc.streamAudio(file);
+    }
+    //TODO sent audio
+}

+ 175 - 0
Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/MegatronService.java

@@ -0,0 +1,175 @@
+package de.nplusc.izc.MegatronBridge;
+
+import de.nplusc.izc.MegatronBridge.Models.CustomAudio;
+import de.nplusc.izc.MegatronBridge.Models.MovementActions;
+import de.nplusc.izc.MegatronBridge.Models.OnboardAudio;
+import de.nplusc.izc.MegatronBridge.Models.RawAction;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Service;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.*;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+@Service
+public class MegatronService
+{
+    public void setVolume(int volume)
+    {
+
+        if(volume>0&&volume<=8)
+        {
+            CommandQueueItem itm = new CommandQueueItem();
+            itm.argument=volume;
+            itm.type=CommandType.VolumeSetter;
+            MegatronBridgeApplication.spammer.getQueue().add(itm);
+        }
+        else
+        {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Out of Range");
+        }
+    }
+    public void executeRaw(RawAction action)
+    {
+        boolean sus=false;
+        if(action.getpsk()==null)
+        {
+            sus=true;
+            System.out.println("it smells fishy");
+        }
+        if(action.getCommand()==null)
+        {
+            sus=true;
+            System.out.println("it smells fishy again");
+        }
+
+        if(!sus&&action.getpsk().equals(MegatronBridgeApplication.PSK))
+        {
+            CommandQueueItem itm = new CommandQueueItem();
+            itm.type=CommandType.RawCommand;
+            itm.extendedArg =action.getCommand();
+            MegatronBridgeApplication.spammer.getQueue().add(itm);
+        }
+        else
+        {
+            throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "from __future__ import braces");
+        }
+    }
+    public void playOnbardAudio(OnboardAudio audio)
+    {
+        int internalId = switch(audio)
+        {
+            case DECEPTICONSRETREAT -> 0; //TODO checken dass die stimmen und vervollständigen
+            case ALLHAILMEGATRON -> 1;
+            case BZZZZZZZRT -> 2;
+            case DECEPTICONSATTACK ->3;
+            case SND_EYELIGHT_ON -> 4;
+            case SND_EYELIGHT_OFF -> 5;
+            case SND_BOOTUP -> 6;
+        };
+        CommandQueueItem itm = new CommandQueueItem();
+        itm.type=CommandType.OnboardAudio;
+        itm.argument=internalId;
+        MegatronBridgeApplication.spammer.getQueue().add(itm);
+    }
+
+    public String[] listAudio()
+    {
+        return audioMapTable.stream().map((o)->o.ID()).toList().toArray(new String[audioMapTable.size()]);
+    }
+
+    public void playCustomAudio(CustomAudio audio)
+    {
+        final String ref = audio.getTargetSample();
+        InternalAudioMapping mapping = audioMapTable.stream().filter(o->o.ID().equals(ref)).findFirst().orElseGet(()->null);
+        if(mapping==null)
+        {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "from __future__ import braces");
+        }
+        int internalId=mapping.index();
+        if(audio.isWiggleMouth())
+        {
+            internalId|=0x1_00_00;
+        }
+        CommandQueueItem itm = new CommandQueueItem();
+        itm.type=CommandType.CustomAudio;
+        itm.argument=internalId;
+        MegatronBridgeApplication.spammer.getQueue().add(itm);
+    }
+
+    public void wiggle(MovementActions action)
+    {
+        int internalId = switch(action)
+        {
+            case EYEGLOW -> 0x6;
+            case EYEDARK -> 0xA;
+
+            case EYEFLICKERING -> 0x2;
+            case EARWIGGLE -> 0xC;
+            case BATTLEMODEON -> 0xE;
+            case BATTLEMODEOFF -> 0x1;
+        };
+        CommandQueueItem itm = new CommandQueueItem();
+        itm.type=CommandType.ServoAction;
+        itm.argument=internalId;
+        MegatronBridgeApplication.spammer.getQueue().add(itm);
+    }
+    public void wiggleMouth()
+    {
+        System.out.println("Mundwerk wiggler");
+        CommandQueueItem itm = new CommandQueueItem();
+        itm.type=CommandType.MundwerkToggle;
+        MegatronBridgeApplication.spammer.getQueue().add(itm);
+    }
+
+    public void streamAudio(MultipartFile file)
+    {
+        if(file.getSize()>60*11000)
+        {
+            throw new ResponseStatusException(HttpStatus.PAYLOAD_TOO_LARGE, "forget it....");
+        }
+        try
+        {
+            CommandQueueItem itm = new CommandQueueItem();
+            itm.type=CommandType.StreamAudio;
+            byte[] tmp = file.getBytes();
+            itm.streamData= Arrays.copyOfRange(tmp,0,tmp.length&(~0b00111111)); //trim down to nearest 64 byte chunk
+            MegatronBridgeApplication.spammer.getQueue().add(itm);
+        } catch (IOException e)
+        {
+            e.printStackTrace();
+            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "oupps");
+        }
+    }
+
+    private List<InternalAudioMapping> audioMapTable = loadMappings();
+
+    private static List<InternalAudioMapping> loadMappings(){
+        LinkedList list = new LinkedList<>();
+        Resource resource = new ClassPathResource("audiomapping.lst");
+        try (BufferedReader in = new BufferedReader(new InputStreamReader(resource.getInputStream()))){
+
+            in.lines().forEach(line->
+            {
+                String[] linesplit = line.split(":");
+                int index = Integer.decode(linesplit[1]);
+                list.add(new InternalAudioMapping(linesplit[0],index));
+            });
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return list;
+    }
+}
+
+
+
+record InternalAudioMapping(String ID, int index)
+{}

+ 28 - 0
Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/Models/CustomAudio.java

@@ -0,0 +1,28 @@
+package de.nplusc.izc.MegatronBridge.Models;
+
+public class CustomAudio
+{
+    private boolean wiggleMouth;
+    private String targetSample;
+
+    public boolean isWiggleMouth()
+    {
+        return wiggleMouth;
+    }
+
+    public void setWiggleMouth(boolean wiggleMouth)
+    {
+        this.wiggleMouth = wiggleMouth;
+    }
+
+    public String getTargetSample()
+    {
+        return targetSample;
+    }
+
+    public void setTargetSample(String targetSample)
+    {
+        this.targetSample = targetSample;
+    }
+}
+

+ 11 - 0
Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/Models/MovementActions.java

@@ -0,0 +1,11 @@
+package de.nplusc.izc.MegatronBridge.Models;
+
+public enum MovementActions
+{
+    EYEGLOW,
+    EYEDARK,
+    EYEFLICKERING,
+    EARWIGGLE,
+    BATTLEMODEON,
+    BATTLEMODEOFF
+}

+ 12 - 0
Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/Models/OnboardAudio.java

@@ -0,0 +1,12 @@
+package de.nplusc.izc.MegatronBridge.Models;
+
+public enum OnboardAudio
+{
+    DECEPTICONSRETREAT,
+    ALLHAILMEGATRON,
+    BZZZZZZZRT,
+    DECEPTICONSATTACK,
+    SND_EYELIGHT_ON,
+    SND_EYELIGHT_OFF,
+    SND_BOOTUP
+}

+ 27 - 0
Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/Models/RawAction.java

@@ -0,0 +1,27 @@
+package de.nplusc.izc.MegatronBridge.Models;
+
+public class RawAction
+{
+    private String command;
+    private String psk;
+
+    public String getCommand()
+    {
+        return command;
+    }
+
+    public void setCommand(String command)
+    {
+        this.command = command;
+    }
+
+    public String getpsk()
+    {
+        return psk;
+    }
+
+    public void setpsk(String PSK)
+    {
+        this.psk = PSK;
+    }
+}

+ 296 - 0
Megatron-Bridge/src/main/java/de/nplusc/izc/MegatronBridge/SerialSpammer.java

@@ -0,0 +1,296 @@
+package de.nplusc.izc.MegatronBridge;
+
+
+import com.fazecast.jSerialComm.SerialPort;
+
+import java.io.*;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.Queue;
+
+enum NextChunkAction
+{
+    WAIT,
+    REPEAT,
+    CONTINUE,
+    FINISHED
+}
+
+public class SerialSpammer
+{
+    private InputStream in = null;
+    private OutputStream o = null;
+    private NextChunkAction nextChunkReady = NextChunkAction.WAIT;
+    private int waitCtr = 0;
+    private Object workaround = new Object();
+    private int streampointer = 0;
+    private Queue<CommandQueueItem> queue= new LinkedList<>();
+    private boolean startedStreamPlayback = false;
+
+    public Queue<CommandQueueItem> getQueue()
+    {
+        return queue;
+    }
+
+    private final char[] hex = "0123456789ABCDEF".toCharArray();
+    private byte[] streamfile = null;
+    public SerialSpammer(String comPortName)
+    {
+
+        System.out.println("Gobblygob");
+
+        int sendOffset = 0;
+        SerialPort comPort = SerialPort.getCommPort(comPortName);
+        comPort.openPort();
+        comPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 0, 0);
+        in = comPort.getInputStream();
+        o = comPort.getOutputStream();
+        new Thread(()->
+
+        {
+            System.out.println("MunchMunchMunch");
+            try
+            {
+                while (true)
+                {
+                    if(in.available()<1)
+                    {
+                        continue;
+                    }
+                    int read = in.read();
+                    if (read == '~')
+                    {
+                        System.out.println("RSME");
+                        nextChunkReady = NextChunkAction.CONTINUE;
+                        synchronized (workaround)
+                        {
+                            System.out.println("POKE");
+                            workaround.notify();
+                        }
+
+                    }
+                    if (read == '<')
+                    {
+                        nextChunkReady = NextChunkAction.REPEAT;
+                        synchronized (workaround)
+                        {
+                            System.out.println("POKE");
+                            workaround.notify();
+                        }
+                    }
+
+                    System.out.write(read);
+                    System.out.flush();
+                }
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace();
+            }
+        }).start();
+
+        new Thread(()->
+
+        {
+        while(true)
+        {
+            CommandQueueItem itm = queue.poll();
+            if(itm != null)
+            {
+                switch (itm.type)
+                {
+                    case ServoAction:
+                        if(itm.argument>15||itm.argument<0)
+                        {
+                            break;
+                        }
+                        try
+                        {
+                            o.write('*');
+                            o.write('S');
+                            o.write(hex[itm.argument]);
+                            o.write('G');
+                        } catch (IOException e)
+                        {
+                            e.printStackTrace();
+                        }
+                        break;
+                    case OnboardAudio:
+                        if(itm.argument>15||itm.argument<0)
+                        {
+                            break;
+                        }
+                        try
+                        {
+                            o.write('*');
+                            o.write('T');
+                            o.write(hex[itm.argument]);
+                            o.write('G');
+                        } catch (IOException e)
+                        {
+                            e.printStackTrace();
+                        }
+                        break;
+                    case CustomAudio:
+                        if(itm.argument<0)
+                        {
+                            break;
+                        }
+                        boolean wiggleMouth = false;
+                        if(itm.argument>0xFFFF)
+                        {
+                            wiggleMouth=true;
+                            itm.argument&=0xFFFF;
+                        }
+                        System.out.println(itm.argument);
+                        LinkedList<Character> reverser = new LinkedList<>();
+                        int arg = itm.argument;
+                        while(arg>0)
+                        {
+                            reverser.add(hex[arg%16]);
+                            arg>>=4;
+                        }
+                        try
+                        {
+                            o.write('*');
+                            while(true)
+                            {
+                                Character c = reverser.pollLast();
+                                if(c==null)
+                                {
+                                    break;
+                                }
+                                o.write(c);
+                                System.out.println("CSEND="+c);
+                            }
+                            o.write(wiggleMouth?'V':'v');
+                        } catch (IOException e)
+                        {
+                            e.printStackTrace();
+                        }
+
+                        break;
+
+                    case StreamAudio:
+                        if(streamfile==null)
+                        {
+                            streamfile = itm.streamData;
+                            nextChunkReady=NextChunkAction.CONTINUE;
+                            synchronized (workaround)
+                            {
+                                System.out.println("POKE");
+                                workaround.notify();
+                            }
+                        }
+                        break;
+                    case MundwerkToggle:
+                        try
+                        {
+                            o.write('M');
+                            try
+                            {
+                                Thread.sleep(10);
+                            } catch (InterruptedException e)
+                            {
+                                e.printStackTrace();
+                            }
+                        } catch (IOException e)
+                        {
+                            e.printStackTrace();
+                        }
+                        break;
+                    case RawCommand:
+                        try
+                        {
+                            for(char c:itm.extendedArg.toCharArray())
+                            {
+                                o.write(c);
+                            }
+                        } catch (IOException e)
+                        {
+                            e.printStackTrace();
+                        }
+                        break;
+                    case VolumeSetter:
+                        try
+                        {
+                            for(int i=0;i<8;i++)
+                            {
+                                    o.write('-');
+                            }
+                            for(int i=0;i<itm.argument;i++)
+                            {
+                                o.write('+');
+                            }
+                        } catch (IOException e)
+                        {
+                            e.printStackTrace();
+                        }
+                    break;
+                }
+            }
+            if(streamfile!=null)
+            {
+                try{
+                if(streampointer>=streamfile.length)
+                {
+                    System.out.println("FINI");
+                    System.err.println("FINI");
+                    streamfile=null;
+                    streampointer=0;
+                    startedStreamPlayback=false;
+                }
+                else
+                {
+                    if((!startedStreamPlayback)&&(streampointer==8192||streampointer==streamfile.length))
+                    {
+                        System.out.println("PLAY");
+                        o.write('|');
+                        startedStreamPlayback=true;
+                    }
+                    switch(nextChunkReady)
+                    {
+                        case REPEAT:
+                            System.out.println("RTRY=("+streampointer+")");
+                            waitCtr=0;
+                            if(streampointer>=64)
+                            {
+                                streampointer-=64;
+                            }
+                        case CONTINUE:
+                            waitCtr=0;
+                            System.out.println("STR=("+streampointer+")");
+                            byte[] readbfr = Arrays.copyOfRange(streamfile,streampointer,streampointer+64);
+                            streampointer+=64;
+                            o.write('>');
+                            nextChunkReady=NextChunkAction.WAIT;
+                            o.write(readbfr);
+
+                            break;
+                    }
+                    synchronized (workaround)
+                    {
+                        if(nextChunkReady==NextChunkAction.WAIT)
+                        {
+                            System.out.println("GOTO WAIT");
+                            try
+                            {
+                                workaround.wait();
+                            } catch (InterruptedException e)
+                            {
+                                e.printStackTrace();
+                            }
+                        }
+                    }
+                }
+                }
+                catch (IOException e)
+                {
+                    System.out.println("Zöinks");
+                    e.printStackTrace();
+                }
+            }
+        }
+        }).start();
+    }
+}

+ 1 - 0
Megatron-Bridge/src/main/resources/application.properties

@@ -0,0 +1 @@
+spring.application.name=MegatronBridge

+ 21 - 0
Megatron-Bridge/src/main/resources/audiomapping.lst

@@ -0,0 +1,21 @@
+ROGERROGER:0
+R2D2_BEEPERY:1
+JFO_SFX_MACHINEPOWERUP:2
+JFO_AUTHENTICATED:3
+JFO_CHARGED_AND_READY:4
+JFO_CORE_PROGRAMMING_MODIFIED:5
+JFO_RECALIBRATING:6
+JFO_SCANNING:7
+JFO_SYSTEM_REBOOTED:8
+JFO_SYSTEM_MALFUNCTION:9
+R2D2_DEMOTIVATED:10
+GB_STARTUP_SOUND:11
+WORMS_BITTEKOMMENGROSSERVOGEL:12
+GLADOS_OHDUBISTES:19
+GLADOS_NICHT_REINFALLEN:20
+GLADOS_PLANB:21
+GLADOS_SEID_IHR_DEFEKT:22
+HALLELUJAH:23
+P2TURRET_FAIL:24
+WORMS_OEDE:25
+OPTIMUSPRIME:26

+ 143 - 0
NETQuickies/SWR1HLSURLGen/Program.cs

@@ -0,0 +1,143 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading;
+
+namespace SWR1HLSURLGen
+{
+    class Program
+    {
+        // wget -nc https://swrevent03hls.akamaized.net/hls/live/2016768-b/event03/20231019T082004/master-720p-3628/00040/master-720p-3628_00034.ts || exit
+        static void Main(string[] args)
+        {
+            //args = new string[] { "livesuck", "1", "1950" };
+            Console.WriteLine(args.Length);
+            bool suckle = false;
+            if (args.Length >= 1)
+            {
+                if (args[0] == "livesuck")
+                {
+                    args = args.Skip(1).ToArray(); //shiftleft 1
+                    suckle = true;
+                }
+            }
+
+            String prefix = "https://swrevent03hls.akamaized.net/hls/live/2016768-b/event03/20240912T144236/master-720p-3628/";
+            String infix = "/master-720p-3628_";
+            String suffix = ".ts";
+
+
+            int startingoffset;
+            int startingsegment;
+            if (args.Length == 5)
+            {
+                prefix = args[0];
+                startingsegment = int.Parse(args[1]);
+                infix = args[2];
+                startingoffset = int.Parse(args[3]);
+                suffix = args[4];
+            }
+            else
+            {
+                startingsegment = int.Parse(args[0]);
+                startingoffset = int.Parse(args[1]);
+            }
+
+            Console.WriteLine(@"#!/bin/bash
+cd /home/web/radiotapes/videotape/segmented");
+
+            bool backfill = true; //XXX
+            if (suckle)
+            {
+                String pathbase = "/home/web/radiotapes/videotape/segmented/autosuckle/";
+
+                int backfillSegment = startingsegment;
+                int backfillOffset = startingoffset;
+                int currentSegment = startingsegment;
+                int currentOffset = startingoffset;
+
+                while(true)
+                {
+                    if (backfill)
+                    {
+                        String backfillSegmentE = currentSegment.ToString("D5");
+                        String backfillOffsetE = currentOffset.ToString("D5");
+                        Console.WriteLine("Backfilling "+ backfillSegmentE + " "+ backfillOffsetE);
+                        Directory.CreateDirectory(pathbase + backfillSegmentE);
+                        Process p = new Process();
+                        p.StartInfo.FileName = "wget";
+                        p.StartInfo.Arguments = "-nc " + prefix + backfillSegmentE + infix + backfillOffsetE + suffix;
+                        p.StartInfo.WorkingDirectory = pathbase + backfillSegmentE;
+                        p.Start();
+                        p.WaitForExit();
+                        if(p.ExitCode>0)
+                        {
+                            Console.WriteLine("Backfill failure, 404, stopping backfill");
+                            backfill = false;
+                        }
+                        backfillOffset--;
+                        if(backfillOffset==0)
+                        {
+                            backfillSegment--;
+                            backfillOffset = 2000;
+                        }
+                    }
+                    if(currentSegment!=backfillSegment||!backfill)
+                    {
+                        String currentSegmentE = currentSegment.ToString("D5");
+                        String currentOffsetE = currentOffset.ToString("D5");
+                        Console.WriteLine("Pulling " + currentSegmentE + " " + currentOffsetE);
+                        //*
+                        Directory.CreateDirectory(pathbase + currentSegmentE);
+                        Process p = new Process();
+                        p.StartInfo.FileName = "wget";
+                        p.StartInfo.Arguments = "-nc " + prefix + currentSegmentE + infix + currentOffsetE + suffix;
+                        p.StartInfo.WorkingDirectory = pathbase + currentSegmentE;
+                        p.Start();
+                        p.WaitForExit();/**/
+                        bool error = p.ExitCode != 0;
+                        if(error)
+                        {
+                            Console.WriteLine("Bonk, need to wait,segment not ready yet");
+                        }
+                        else
+                        {
+                            currentOffset++;
+                            if(currentOffset>2000)
+                            {
+                                currentOffset = 1;
+                                currentSegment++;
+                            }
+
+                        }
+                        if (!backfill)
+                        {
+                            Thread.Sleep(2000);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                for (int i = startingsegment; i < startingsegment + 100; i++)
+                {
+                    String outeridx = i.ToString("D5");
+                    Console.WriteLine("mkdir -p " + outeridx);
+                    Console.WriteLine("cd " + outeridx);
+                    int innerstart = 1;
+                    if (i == startingsegment) //edgecase first loop
+                    {
+                        innerstart = startingoffset;
+                    }
+                    for (int j = innerstart; j <= 2000; j++)
+                    {
+                        String inneridx = j.ToString("D5");
+                        Console.WriteLine("wget -nc " + prefix + outeridx + infix + inneridx + suffix + " || exit");
+                    }
+                    Console.WriteLine("cd ..");
+                }
+            }
+        }
+    }
+}

+ 8 - 0
NETQuickies/SWR1HLSURLGen/SWR1HLSURLGen.csproj

@@ -0,0 +1,8 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net5.0</TargetFramework>
+  </PropertyGroup>
+
+</Project>

+ 25 - 0
NETQuickies/SWR1HLSURLGen/SWR1HLSURLGen.sln

@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31321.278
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SWR1HLSURLGen", "SWR1HLSURLGen.csproj", "{D4E39A1E-5DE7-42D4-AA9A-BB55FEBC29FD}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D4E39A1E-5DE7-42D4-AA9A-BB55FEBC29FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D4E39A1E-5DE7-42D4-AA9A-BB55FEBC29FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D4E39A1E-5DE7-42D4-AA9A-BB55FEBC29FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D4E39A1E-5DE7-42D4-AA9A-BB55FEBC29FD}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {31554B07-3899-4C5F-A236-D5932842FA52}
+	EndGlobalSection
+EndGlobal

+ 3 - 1
QuickStuff/build.gradle

@@ -3,7 +3,7 @@ defaultTasks 'distZip'
 apply plugin: 'java-library'
 apply plugin: 'application'
 
-mainClassName = 'GPN.BotGame'
+mainClassName = 'QuickVerifyCrap.SerialSpammer'
 sourceCompatibility = 1.17
 dependencies{
     api(project(':ToolKit')) {
@@ -11,4 +11,6 @@ dependencies{
     implementation 'org.bouncycastle:bcprov-ext-jdk18on:1.71'
     implementation 'com.fazecast:jSerialComm:[2.0.0,3.0.0)'
     implementation 'com.eclipsesource.minimal-json:minimal-json:0.9.5'
+    implementation 'org.apache.httpcomponents:httpclient:4.5.14'
+    implementation 'org.seleniumhq.selenium:selenium-java:4.27.0'
 }

+ 2 - 2
QuickStuff/src/main/java/PV/UI.java

@@ -22,8 +22,8 @@ public class UI extends javax.swing.JFrame
     {
         initComponents();
         
-        String fp = "C:\\Users\\LH\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\wb5ap89r.default\\places.sqlite";
-        String fp2="C:\\lmaa\\imgur-hunt.txt";
+        String fp = "C:\\Users\\LH\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\wb5ap89r.default\\places - Kopie.sqlite";
+        String fp2="C:\\lmaa\\fickdichhärter.txt";
         DBWriter dbw = new DBWriter("", fp, "", "", DBWriter.DBTYPE_SQLite);
         //String[][] items = dbw.queryTable("SELECT url , id FROM moz_places");
         String[][] idmap = dbw.queryTable("SELECT place_id , visit_date from moz_historyvisits  ORDER BY visit_date");

+ 23 - 0
QuickStuff/src/main/java/QuickVerifyCrap/ByteZilser.java

@@ -0,0 +1,23 @@
+package QuickVerifyCrap;
+
+import java.io.FileNotFoundException;
+import java.io.RandomAccessFile;
+
+public class ByteZilser
+{
+    public static void main(String[] args) throws Exception
+    {
+        RandomAccessFile r = new RandomAccessFile("/home/tgoerner/loa/000028/h4xxz0ring-addon/PicoMergedCode/debuggenerated.bin","rw");
+        for(int rp=0;rp<100;rp++)
+        {
+            for(int i=0;i<256;i++)
+            {
+                for (int j=0;j<11;j++)
+                {
+                    r.write(i);
+                }
+            }
+        }
+        r.close();
+    }
+}

+ 95 - 0
QuickStuff/src/main/java/QuickVerifyCrap/CSVFlashMassageliege.java

@@ -0,0 +1,95 @@
+package QuickVerifyCrap;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.RandomAccessFile;
+
+public class CSVFlashMassageliege
+{
+    public static void main(String[] args)  throws Exception
+    {
+        BufferedReader r = new BufferedReader(new FileReader("D:\\loa\\000023\\002\\flashsnarf-export-moredata.csv"));
+        String line = r.readLine();
+        RandomAccessFile f = new RandomAccessFile("D:\\loa\\000023\\002\\flashsnarf-processed2.bin","rw");
+        line = r.readLine(); //LMAA header
+        State current = State.IDLE;
+        int parambytes = 0;
+        int seek=0;
+        while(line !=null&&line.length()>1)
+        {
+            System.out.println(line);
+            System.out.println(current);
+            String[] linesplitted = line.split(",");
+            if (linesplitted[1].equals("\"disable\""))
+            {
+                current = State.IDLE;
+            }
+            if (current !=State.SKIP) //ignoring lines until disable when skipping a TXN
+            {
+                if (linesplitted[1].equals("\"enable\""))
+                {
+                    if (current != State.IDLE)
+                    {
+                        System.err.println("WADDAFUQ?");
+                    } else
+                    {
+                        current = State.COMMAND;
+                    }
+                }
+                if (linesplitted[1].equals("\"result\""))
+                {
+                    switch(current)
+                    {
+                        case PARAMS:
+                            if(parambytes<3)
+                            {
+                                int value = Integer.decode(linesplitted[4]);
+                                System.out.println(value);
+                                seek=(seek<<8)+value;
+                                parambytes++;
+                            }
+                            if(parambytes==3)
+                            {
+                                System.out.println(seek);
+                                f.seek(seek);
+                                parambytes=0;
+                                seek=0; //readying for next txn
+                                current=State.RESULT;
+                            }
+                            break;
+                        case COMMAND:
+                            if(linesplitted[4].equals("0x03"))
+                            {
+                                current=State.PARAMS;
+                            }
+                            else
+                            {
+                                current=State.SKIP;
+                            }
+                            break;
+                        case RESULT:
+                            int value = Integer.decode(linesplitted[5]);
+                            f.write(new byte[]{(byte)value});
+                            break;
+                    }
+                }
+            }
+
+            line = r.readLine();
+        }
+        f.close();
+    }
+
+
+
+
+}
+
+enum State
+{
+    IDLE,
+    COMMAND,
+    PARAMS,
+    RESULT,
+    SKIP
+}

+ 10 - 7
QuickStuff/src/main/java/QuickVerifyCrap/CSVMassageliege.java

@@ -8,23 +8,25 @@ public class CSVMassageliege
 {
     public static void main(String[] args) throws Exception
     {
-        BufferedReader r = new BufferedReader(new FileReader("D:\\loa\\000028\\004\\pico-tapes\\on_switchoff.csv"));
+        BufferedReader r = new BufferedReader(new FileReader("D:\\loa\\000002\\001\\masseuse\\analog.csv"));
         String line = r.readLine();
-        RandomAccessFile f = new RandomAccessFile("D:\\loa\\000028\\004\\pico-tapes\\on_switchoff.raw","rw");
+        RandomAccessFile f = new RandomAccessFile("D:\\loa\\000002\\001\\masseuse\\massiert.raw","rw");
         line = r.readLine(); //LMAA header
         line = r.readLine();
         line = r.readLine();
-        String firstSampleOffset = line.replace(',','.').split(";")[0];
+        //String firstSampleOffset = line.replace(',','.').split(";")[0];
+        String firstSampleOffset = line.split(",")[0];
         String lastSampleoffset = "0.0";
         int i=0;
-        while(line !=null)
+        while(line !=null&&line.length()>1)
         {
-            String[] linesplitted = line.replace(',','.').split(";");
+            //tring[] linesplitted = line.replace(',','.').split(";");
+            String[] linesplitted = line.split(",");
             String sampleraw = linesplitted[linesplitted.length-1];
             if(!sampleraw.equalsIgnoreCase("nan"))
             {
                 sampleraw = sampleraw.replace("∞","1000000.0");
-                double sample = Double.valueOf(sampleraw);
+                double sample = Double.valueOf(sampleraw)-1.25;
                 double sampleCrunch = (sample/1.0)*32768.0;
 
                 short intSample = (short)Math.max(-32768,(Math.min(32767,sampleCrunch)));
@@ -34,7 +36,8 @@ public class CSVMassageliege
                 {
                     System.out.println("i="+i);
                 }
-                lastSampleoffset = line.replace(',','.').split(";")[0];
+                //lastSampleoffset = line.replace(',','.').split(";")[0];
+                lastSampleoffset = line.split(",")[0];
             }
             line=r.readLine();
         }

+ 67 - 0
QuickStuff/src/main/java/QuickVerifyCrap/ChaosPostSpammer.java

@@ -0,0 +1,67 @@
+package QuickVerifyCrap;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.firefox.FirefoxDriver;
+
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+
+public class ChaosPostSpammer
+{
+    public static void main(String[] args) throws Exception
+    {
+        BufferedReader r = new BufferedReader(new FileReader("C:\\lmaa\\38c3spam.lst"));
+        WebDriver driver = new FirefoxDriver();
+        PrintWriter w = new PrintWriter(new FileWriter("C:\\lmaa\\38c3spam.sh"));
+
+        w.println("#!/bin/bash");
+        String line = r.readLine();
+        while(line !=null)
+        {
+            String[] linesplitted = line.split("\\|");
+            for(int i=0;i<linesplitted.length;i++)
+            {
+                if(linesplitted[i].length()>20)
+                {
+                    linesplitted[i]=linesplitted[i].substring(0,20);
+                }
+            }
+            line = String.join("\n",linesplitted);
+            driver.get("https://office.c3post.de/");
+            driver.manage().timeouts().implicitlyWait(Duration.ofMillis(2500));
+
+            WebElement sender = driver.findElement(By.id("sender"));
+            WebElement rcpt = driver.findElement(By.id("receiver"));
+            WebElement content = driver.findElement(By.id("message"));
+            WebElement checkbox = driver.findElement(By.id("check"));
+            WebElement submit = driver.findElement(By.xpath("/html/body/div[2]/div/div[2]/form"));
+
+            sender.sendKeys("Murphy's\n" +
+                    "Sabotageservice");
+            rcpt.sendKeys(line);
+            content.sendKeys("Murphy's Sabotageservice\n" +
+                    "Wir funken dazwischen, verpfuschen, versauen und grillen ihre Technik!\n" +
+                    "Beauftragung erfolgt unaufgefordert selbstständig.\n" +
+                    "\n" +
+                    "We sabotage, mess up, cook and burninate your tech!\n" +
+                    "Work is scheduled unannounced.");
+            checkbox.click();
+            Thread.sleep(2500);
+            submit.submit();
+            Thread.sleep(2500);
+            //String spamtemplate = "curl 'https://office.c3post.de/' -X POST -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate, br, zstd' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Origin: https://office.c3post.de' -H 'Connection: keep-alive' -H 'Referer: https://office.c3post.de/' -H 'Cookie: session=eyJfZnJlc2giOmZhbHNlLCJjc3JmX3Rva2VuIjoiMmU4MzFmMzZjYjdhNzUwMzg1MGY3MmM0OWRiMzVjYTg5N2Q0MGE2YiJ9.Z2miJw.R0933HCAUWSk3VdhqzKMPJk0b-o' -H 'Upgrade-Insecure-Requests: 1' -H 'Sec-Fetch-Dest: document' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-Site: same-origin' -H 'Sec-Fetch-User: ?1' -H 'Priority: u=0, i' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache' -H 'TE: trailers' --data-raw 'csrf_token=IjJlODMxZjM2Y2I3YTc1MDM4NTBmNzJjNDlkYjM1Y2E4OTdkNDBhNmIi.Z2miJw.9wTZSC--9gRoBPbMSFFbXb7pdWY&from_event_id=18&to_event_id=18&postcard_id=-1&sender=Murphy%27s%0D%0ASabotageservice&receiver="
+            //        + URLEncoder.encode(line, StandardCharsets.UTF_8)
+            //        +"&message=Murphy%27s+Sabotageservice%0D%0AWir+funken+dazwischen%2C+verpfuschen%2C+versauen+und+grillen+ihre+Technik%21%0D%0ABeauftragung+erfolgt+unaufgefordert+selbstst%C3%A4ndig.%0D%0A%0D%0AWe+sabotage%2C+mess+up%2C+cook+and+burninate+your+tech%21%0D%0AWork+is+scheduled+unannounced.&check=y'";
+            //w.println(spamtemplate);
+
+            
+            line=r.readLine();
+        }
+        w.close();
+        driver.quit();
+    }
+}

+ 188 - 0
QuickStuff/src/main/java/QuickVerifyCrap/SerialSpammer.java

@@ -0,0 +1,188 @@
+package QuickVerifyCrap;
+
+import com.fazecast.jSerialComm.SerialPort;
+
+import javax.sql.rowset.serial.SQLOutputImpl;
+import java.io.*;
+
+enum NextChunkAction
+{
+    WAIT,
+    REPEAT,
+    CONTINUE,
+    FINISHED
+}
+
+public class SerialSpammer
+{
+    static InputStream in = null;
+    static OutputStream o = null;
+    static NextChunkAction nextChunkReady = NextChunkAction.WAIT;
+    static int waitCtr = 0;
+    static Object workaround = new Object();
+    public static void main(String[] args)
+    {
+        boolean startedStreamPlayback = false;
+        System.out.println("Gobblygob");
+        RandomAccessFile streamfile = null;
+        int sendOffset = 0;
+        SerialPort comPort = SerialPort.getCommPort("COM20");
+        comPort.openPort();
+        comPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 0, 0);
+        in = comPort.getInputStream();
+        o = comPort.getOutputStream();
+        try
+        {
+            new Thread(()->
+            
+            {
+                System.out.println("MunchMunchMunch");
+                try
+                {
+                    while (true)
+                    {
+                        if(in.available()<1)
+                        {
+                            continue;
+                        }
+                        int read = in.read();
+                        if (read == '~')
+                        {
+                            System.out.println("RSME");
+                            nextChunkReady = NextChunkAction.CONTINUE;
+                            synchronized (workaround)
+                            {
+                                System.out.println("POKE");
+                                workaround.notify();
+                            }
+
+                        }
+                        if (read == '<')
+                        {
+                            nextChunkReady = NextChunkAction.REPEAT;
+                            synchronized (workaround)
+                            {
+                                System.out.println("POKE");
+                                workaround.notify();
+                            }
+                        }
+
+                        System.out.write(read);
+                        System.out.flush();
+                    }
+                }
+                catch (IOException e)
+                {
+                    e.printStackTrace();
+                }
+            }).start();
+            
+            
+            while(true)
+            {
+                if(System.in.available()>0)
+                {
+                    int chara = System.in.read();
+                    if(chara ==-1)
+                    {
+                        System.out.println("ZÖINKS");
+                        return;
+                    }
+                    if(chara == '>')
+                    {
+                        char[] filepath = new char[4096];
+                        int pathptr = 0;
+                        chara = System.in.read();
+                        while(chara != '\n'&&pathptr<4096)
+                        {
+                            filepath[pathptr]=(char)chara;
+                            pathptr++;
+                            chara = System.in.read();
+                        }
+                        if(pathptr==4096)
+                        {
+                            System.out.println("Zarf, pathdork");
+                        }
+                        else
+                        {
+                            String path = new String(filepath).split("\u0000")[0];
+                            System.out.println("Streaming: "+path);
+                            if(new File(path).exists())
+                            {
+                                streamfile = new RandomAccessFile(path,"r");
+                                nextChunkReady=NextChunkAction.CONTINUE;
+                                synchronized (workaround)
+                                {
+                                    System.out.println("POKE");
+                                    workaround.notify();
+                                }
+                            }
+                        }
+                    }
+                    else
+                    {
+                        //System.out.println("Fuick");
+                        o.write(chara);
+                        o.flush();
+                        if(chara=='\n')
+                        {
+                            System.out.println("waitctr="+waitCtr);
+                        }
+                        //System.out.println("ZilseZilse");
+                    }
+                }
+                if(streamfile!=null)
+                {
+
+                    if(streamfile.getFilePointer()>=streamfile.length())
+                    {
+                        System.out.println("FINI");
+                        System.err.println("FINI");
+                        streamfile.close();
+                        streamfile=null;
+                        startedStreamPlayback=false;
+                    }
+                    else
+                    {
+                        if((!startedStreamPlayback)&&(streamfile.getFilePointer()==8192||streamfile.getFilePointer()==streamfile.length()))
+                        {
+                            System.out.println("PLAY");
+                            o.write('|');
+                            startedStreamPlayback=true;
+                        }
+                        switch(nextChunkReady)
+                        {
+                            case REPEAT:
+                                System.out.println("RTRY=("+streamfile.getFilePointer()+")");
+                                waitCtr=0;
+                                if(streamfile.getFilePointer()>=64)
+                                {
+                                    streamfile.seek(streamfile.getFilePointer()-64);
+                                }
+                            case CONTINUE:
+                                waitCtr=0;
+                                System.out.println("STR=("+streamfile.getFilePointer()+")");
+                                byte[] readbfr = new byte[64];
+                                streamfile.read(readbfr);
+                                o.write('>');
+                                nextChunkReady=NextChunkAction.WAIT;
+                                o.write(readbfr);
+
+                            break;
+                        }
+                        synchronized (workaround)
+                        {
+                            if(nextChunkReady==NextChunkAction.WAIT)
+                            {
+                                System.out.println("GOTO WAIT");
+                                workaround.wait();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        catch (Exception e) { e.printStackTrace(); }
+        comPort.closePort();
+    }
+}

+ 82 - 0
QuickStuff/src/main/java/QuickVerifyCrap/WURestoreZuzel.java

@@ -0,0 +1,82 @@
+package QuickVerifyCrap;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+
+
+
+public class WURestoreZuzel {
+    static String updatesearchmagic = "<SOAP:Envelope xmlns:SOAP=\"x-schema:http://schemas.xmlsoap.org/soap/envelope/\"><SOAP:Body><GetManifest><clientInfo xmlns=\"x-schema:http://schemas.windowsupdate.com/iu/clientInfo.xml\" clientName=\"IU_Site\"/><systemInfo xmlns=\"x-schema:http://schemas.windowsupdate.com/iu/systeminfoschema.xml\"><computerSystem xmlns=\"\" manufacturer=\"VMware, Inc.\" model=\"VMware Virtual Platform\" supportSite=\"\" administrator=\"1\"><driveSpace drive=\"c:\\\" kbytes=\"125047488\"/></computerSystem><platform xmlns=\"\" name=\"VER_PLATFORM_WIN32_WINDOWS\"><processorArchitecture>x86</processorArchitecture><version major=\"4\" minor=\"10\" build=\"2222\" servicePackMajor=\"0\" servicePackMinor=\"0\"/></platform><locale xmlns=\"\" context=\"OS\"><language>de</language></locale><locale xmlns=\"\" context=\"USER\"><language>de</language></locale></systemInfo><query href=\"http://v4.windowsupdaterestored.com/getmanifest.asp\"><dObjQueryV1 procedure=\"Items\"><parentItems><item>win98se.windows98andwindows98secondedition</item></parentItems></dObjQueryV1></query></GetManifest></SOAP:Body></SOAP:Envelope>\n";
+    static String fileidmagic = "<SOAP:Envelope xmlns:SOAP=\"x-schema:http://schemas.xmlsoap.org/soap/envelope/\"><SOAP:Body><GetManifest><clientInfo xmlns=\"x-schema:http://schemas.windowsupdate.com/iu/clientInfo.xml\" clientName=\"IU_Site\"/><systemInfo xmlns=\"x-schema:http://schemas.windowsupdate.com/iu/systeminfoschema.xml\"><computerSystem xmlns=\"\" manufacturer=\"VMware, Inc.\" model=\"VMware Virtual Platform\" supportSite=\"\" administrator=\"1\"><driveSpace drive=\"c:\\\" kbytes=\"125042400\"/></computerSystem><platform xmlns=\"\" name=\"VER_PLATFORM_WIN32_WINDOWS\"><processorArchitecture>x86</processorArchitecture><version major=\"4\" minor=\"10\" build=\"2222\" servicePackMajor=\"0\" servicePackMinor=\"0\"/></platform><locale xmlns=\"\" context=\"OS\"><language>de</language></locale><locale xmlns=\"\" context=\"USER\"><language>de</language></locale></systemInfo><query href=\"http://v4.windowsupdaterestored.com/getmanifest.asp\"><dObjQueryV1 procedure=\"Installation\"><parentItems><item>########</item></parentItems></dObjQueryV1></query></GetManifest></SOAP:Body></SOAP:Envelope>\n";
+    public static void main(String[] args) throws IOException {
+        HttpClient httpclient = HttpClients.createDefault();
+        HttpPost httppost = new HttpPost("http://v4.windowsupdaterestored.com/getmanifest.asp");
+        httppost.setHeader("Content-Type","text/xml");
+        httppost.setHeader("Accept-Language","de");
+        httppost.setHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)");
+// Request parameters and other properties.
+        httppost.setEntity(new StringEntity(updatesearchmagic));
+
+//Execute and get the response.
+        HttpResponse response = httpclient.execute(httppost);
+        HttpEntity entity = response.getEntity();
+
+        if (entity != null) {
+            try (InputStream instream = entity.getContent()) {
+                BufferedReader r = new BufferedReader(new InputStreamReader(instream));
+                String muschipilze = r.readLine();
+                muschipilze = muschipilze.replace("<","<\n");
+                String[] zilsItHarder = muschipilze.split("\n");
+                for (String zilsme:
+                     zilsItHarder) {
+                    if(zilsme.contains("win98se.windows"))
+                    {
+                        String suckleItHarder = zilsme.split("\"")[1];
+                        String pullxml = fileidmagic.replace("########",suckleItHarder);
+
+                        httppost = new HttpPost("http://v4.windowsupdaterestored.com/getmanifest.asp");
+                        httppost.setHeader("Content-Type","text/xml");
+                        httppost.setHeader("Accept-Language","de");
+                        httppost.setHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)");
+// Request parameters and other properties.
+                        httppost.setEntity(new StringEntity(pullxml));
+
+//Execute and get the response.
+                        response = httpclient.execute(httppost);
+                        entity = response.getEntity();
+
+                        if (entity != null) {
+                            try (InputStream instream2 = entity.getContent()) {
+                                BufferedReader r2 = new BufferedReader(new InputStreamReader(instream2));
+                                String muschipilze2 = r2.readLine();
+                                muschipilze2 = muschipilze2.replace("<","<\n");
+                                String[] filezilser = muschipilze2.split("\n");
+                                for (String files:filezilser)
+                                {
+                                    if(files.contains("CabPool")&&files.contains("codeBase"))
+                                    {
+                                        //System.out.println(files);
+                                        System.out.println(files.split("\"")[1]);
+                                    }
+                                }
+
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 16 - 0
QuickStuff/src/main/java/QuickVerifyCrap/Zilsnerator.java

@@ -0,0 +1,16 @@
+package QuickVerifyCrap;
+
+public class Zilsnerator
+{
+    public static void main(String[] args)
+    {
+        char[] hex = "0123456789ABCDEF".toCharArray();
+        for(int i=0;i<16;i++)
+        {
+            for(int j=0;j<16;j++)
+            {
+                System.out.print(" 0x"+hex[i]+hex[j]);
+            }
+        }
+    }
+}

+ 1 - 1
SenaBitWiggler/src/main/java/de/nplusc/izc/senabitwiggler/FirmwareAutoDumper.java

@@ -34,7 +34,7 @@ public class FirmwareAutoDumper
     public static HashMap<String,FirmwareVersion> supprCache = new HashMap<>();
 
     private static final String[] hackfixsuffixes = new String[]
-            {"-rc","rc","-build","build"};
+            {"-rc","rc","-build","_build","build"};
 
     private static final String[] fileextensionfuckyous = new String[]
             {"Pro.img"};

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

@@ -117,8 +117,8 @@ public class PlayListEditAPI
                     }
                     else
                     {                                                   //denk an die API oder es hagelt mysteryerrors
-                        String t1=((SinglePlayListItem)o1).getTitle().split(",")[1].trim();
-                        String t2=((SinglePlayListItem)o2).getTitle().split(",")[1].trim();
+                        String t1=o1.getTitle().split(",")[1].trim();
+                        String t2=o2.getTitle().split(",")[1].trim();
                         int r=t1.compareToIgnoreCase(t2);
                         r=r>0?1:r<0?-1:0;
                         l.trace("Sorter: single_single:"+r+"\ncomparing"+t1+" and "+t2+"\n");

+ 5 - 0
iZplPlugins/Editor/src/main/java/de/nplusc/izc/izpl/plugins/editor/Editor.java

@@ -25,6 +25,7 @@ import de.nplusc.izc.iZpl.API.shared.SinglePlayListItem;
 import de.nplusc.izc.tools.baseTools.Tools;
 import net.java.truevfs.access.TFile;
 import java.awt.EventQueue;
+import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -183,6 +184,10 @@ public class Editor implements FeaturePlugin
         
         List<SinglePlayListItem> data = IZPLApi.readPlayList(path);
         PlayListFile f = new PlayListFile();
+        if(new File(path).isDirectory())
+        {
+            f.setSynthetic(true);
+        }
         f.setPath(path);
         f.setEntries(data);
         lookupCache.put(path, f);

+ 118 - 108
izpl-shared/src/main/java/de/nplusc/izc/iZpl/API/shared/PlayListFile.java

@@ -1,109 +1,119 @@
-/*
- * 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.List;
-import java.util.Objects;
-
-/**
- *
- * @author iZc <nplusc.de>
- */
-public class PlayListFile
-{
-    private List<SinglePlayListItem> entries;
-    
-    private int calculatedBasePriority=1;
-
-    public int getCalculatedBasePriority()
-    {
-        return calculatedBasePriority;
-    }
-
-    public void setCalculatedBasePriority(int calculatedBasePriority)
-    {
-        this.calculatedBasePriority = calculatedBasePriority;
-    }
-    
-    
-    public List<SinglePlayListItem> getEntries()
-    {
-        return entries;
-    }
-
-    public void setEntries(List<SinglePlayListItem> entries)
-    {
-        this.entries = entries;
-    }
-
-    public String getPath()
-    {
-        return path;
-    }
-
-    public void setPath(String path)
-    {
-        this.path = path;
-    }
-    private String path;
-
-    @Override
-    public int hashCode()
-    {
-        int hash = 3;
-        //hash = 41 * hash + Objects.hashCode(this.entries);// fickdich, du funkst beim rumfuhrwerken an den daten beim edit rein
-        hash = 41 * hash + Objects.hashCode(this.path);
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (obj == null)
-        {
-            return false;
-        }
-        if (getClass() != obj.getClass())
-        {
-            return false;
-        }
-        final PlayListFile other = (PlayListFile) obj;
-        if (!Objects.equals(this.entries, other.entries))
-        {
-            return false;
-        }
-        if (!Objects.equals(this.path, other.path))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public String toString()
-    {
-        return "PlayListFile{" + "calculatedBasePriority=" + calculatedBasePriority + ", path=" + path + '}';
-    }
-    
-    public String[] getSuffix()
-    {
-        return new String[]{};
-    }
-    
-    
+/*
+ * 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.List;
+import java.util.Objects;
+
+/**
+ *
+ * @author iZc <nplusc.de>
+ */
+public class PlayListFile
+{
+    private List<SinglePlayListItem> entries;
+    
+    private int calculatedBasePriority=1;
+
+    public int getCalculatedBasePriority()
+    {
+        return calculatedBasePriority;
+    }
+
+
+
+    private boolean synthetic = false;
+
+    public void setCalculatedBasePriority(int calculatedBasePriority)
+    {
+        this.calculatedBasePriority = calculatedBasePriority;
+    }
+    
+    
+    public List<SinglePlayListItem> getEntries()
+    {
+        return entries;
+    }
+
+    public void setEntries(List<SinglePlayListItem> entries)
+    {
+        this.entries = entries;
+    }
+
+    public String getPath()
+    {
+        return path;
+    }
+
+    public void setPath(String path)
+    {
+        this.path = path;
+    }
+    private String path;
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 3;
+        //hash = 41 * hash + Objects.hashCode(this.entries);// fickdich, du funkst beim rumfuhrwerken an den daten beim edit rein
+        hash = 41 * hash + Objects.hashCode(this.path);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        final PlayListFile other = (PlayListFile) obj;
+        if (!Objects.equals(this.entries, other.entries))
+        {
+            return false;
+        }
+        if (!Objects.equals(this.path, other.path))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "PlayListFile{" + "calculatedBasePriority=" + calculatedBasePriority + ", path=" + path + '}';
+    }
+    
+    public String[] getSuffix()
+    {
+        return new String[]{};
+    }
+
+    public boolean isSynthetic() {
+        return synthetic;
+    }
+
+    public void setSynthetic(boolean synthetic) {
+        this.synthetic = synthetic;
+    }
 }

+ 70 - 59
izpl-shared/src/main/java/de/nplusc/izc/iZpl/API/shared/RawPlayListFile.java

@@ -1,59 +1,70 @@
-/*
- * 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.List;
-
-/**
- *
- * @author iZc <nplusc.de>
- */
-public class RawPlayListFile
-{
-    private String[] suffix;
-    
-    private String rootPath;
-    private List<SinglePlayListItem> data;
-
-    public RawPlayListFile(String rootPath, List<SinglePlayListItem> data)
-    {
-        this.rootPath = rootPath;
-        this.data = data;
-        suffix = new String[]{};
-    }
-    
-    public RawPlayListFile(String rootPath, List<SinglePlayListItem> data,String[] suffix)
-    {
-        this.rootPath = rootPath;
-        this.data = data;
-        this.suffix=suffix;
-    }
-    
-    public String getRootPath()
-    {
-        return rootPath;
-    }
-
-    public List<SinglePlayListItem> getData()
-    {
-        return data;
-    }
-    public String[] getSuffix()
-    {
-        return suffix;
-    }
-}
+/*
+ * 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.List;
+
+/**
+ *
+ * @author iZc <nplusc.de>
+ */
+public class RawPlayListFile
+{
+    private String[] suffix;
+    
+    private String rootPath;
+    private List<SinglePlayListItem> data;
+
+    public RawPlayListFile(String rootPath, List<SinglePlayListItem> data)
+    {
+        this.rootPath = rootPath;
+        this.data = data;
+        suffix = new String[]{};
+    }
+    
+    public RawPlayListFile(String rootPath, List<SinglePlayListItem> data,String[] suffix)
+    {
+        this.rootPath = rootPath;
+        this.data = data;
+        this.suffix=suffix;
+    }
+    
+    public String getRootPath()
+    {
+        return rootPath;
+    }
+
+    public List<SinglePlayListItem> getData()
+    {
+        return data;
+    }
+    public String[] getSuffix()
+    {
+        return suffix;
+    }
+
+    private boolean synthetic = false;
+
+    public boolean isSynthetic() {
+        return synthetic;
+    }
+
+    public void setSynthetic(boolean synthetic) {
+        this.synthetic = synthetic;
+    }
+
+}

+ 13 - 4
izpl-shared/src/main/java/de/nplusc/izc/iZpl/Utils/shared/PLFileIO.java

@@ -32,6 +32,7 @@ import java.io.InputStreamReader;
 import java.io.RandomAccessFile;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -106,7 +107,9 @@ public class PLFileIO
             }
             
         }
-        return new RawPlayListFile(path, virtualList);
+        RawPlayListFile rpl =  new RawPlayListFile(path, virtualList);
+        rpl.setSynthetic(true);
+        return rpl;
     }
     
     
@@ -483,6 +486,12 @@ public class PLFileIO
     
     public static void writePLFile(PlayListFile f)
     {
+        if(f.isSynthetic())
+        {
+            l.info("can't save a synthetic file");
+            l.info("file: "+f.getPath());
+            return;
+        }
         // Arbeit mit derPath-Klasse & der File.getPath() methode, Reflection dient zur Kompatibilität mitSystemen ohne dieser Klasse (wie Androiden)
         try{
             boolean supportinRelativeness=false;
@@ -515,7 +524,7 @@ public class PLFileIO
                     if(supportinRelativeness)
                     {
                         Method rel=pathclass.getMethod("relativize", (Class)pathclass);
-                        File current = new File(pathOfFile);
+                        File current = new File(pathOfFile).getCanonicalFile();
                         Object pa = pfadheraberdalli.invoke(current);
                         l.trace("pa-Class:"+pa.getClass());
                         Object figgdi = rel.invoke(basepath, pa);
@@ -523,7 +532,7 @@ public class PLFileIO
                         pathOfFile=figgdi+"";
                     }
                            // = p.relativize(new File().toPath()).toString();
-
+                    pathOfFile=pathOfFile.replace("\\","/"); //windoze-pfade umlegen
 
                     if(pli.isIncludeElement())
                     {
@@ -536,7 +545,7 @@ public class PLFileIO
                 }
                 RandomAccessFile file = new RandomAccessFile(fp, "rw");
                 file.setLength(0);
-                file.write(pld.getBytes());
+                file.write(pld.getBytes(Charset.forName("utf8")));
                 file.close();
             }
             catch (IOException ex)

+ 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:discordjukebox","SenaBitWiggler","PlaceDECSVWiggler","SplitSecondARKiver","GPNBots"
+"iZplPlugins:Extractor","spungit_deathtimer","iZplPlugins:discordjukebox","SenaBitWiggler","PlaceDECSVWiggler","SplitSecondARKiver","GPNBots","Megatron-Bridge"