diff --git a/.idea/encodings.xml b/.idea/encodings.xml
index eccafc183acbddc53097dae4f91cf41f05d2b421..c1500a33cb5596556ab38560f449acbae8fbe473 100644
--- a/.idea/encodings.xml
+++ b/.idea/encodings.xml
@@ -16,6 +16,7 @@
     <file url="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginAwake" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginAwake/src/main/java" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginAwake/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginEqualizer" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginEqualizer/src/main/java" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginEqualizer/src/main/resources" charset="UTF-8" />
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 8f099dcf1c0f4d54403502bdf9db55780d811921..ca57f98e5686aa62d0af34128539b5e49bdf8acc 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -33,7 +33,6 @@
     <option name="ignoredFiles">
       <set>
         <option value="$PROJECT_DIR$/PlayWall/PlayWallComponents/pom.xml" />
-        <option value="$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginContentPlayer/pom.xml" />
       </set>
     </option>
   </component>
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 71a1574f2f6df494b2028c78bb51cb89fc3ba39e..ae20783ca82797f27ca5b049467c233d031158e8 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -7,6 +7,7 @@
       <module fileurl="file://$PROJECT_DIR$/PlayWallCore/PlayWallCore.iml" filepath="$PROJECT_DIR$/PlayWallCore/PlayWallCore.iml" />
       <module fileurl="file://$PROJECT_DIR$/PlayWallDesktop.iml" filepath="$PROJECT_DIR$/PlayWallDesktop.iml" />
       <module fileurl="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginAwake/PlayWallPluginAwake.iml" filepath="$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginAwake/PlayWallPluginAwake.iml" />
+      <module fileurl="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginContentPlayer/PlayWallPluginContentPlayer.iml" filepath="$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginContentPlayer/PlayWallPluginContentPlayer.iml" />
       <module fileurl="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginEqualizer/PlayWallPluginEqualizer.iml" filepath="$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginEqualizer/PlayWallPluginEqualizer.iml" />
       <module fileurl="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginLaunchpad/PlayWallPluginLaunchpad.iml" filepath="$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginLaunchpad/PlayWallPluginLaunchpad.iml" />
       <module fileurl="file://$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginMedia/PlayWallPluginMedia.iml" filepath="$PROJECT_DIR$/PlayWallPlugins/PlayWallPluginMedia/PlayWallPluginMedia.iml" />
diff --git a/PlayWall/src/main/java/de/tobias/playpad/PlayPadMain.java b/PlayWall/src/main/java/de/tobias/playpad/PlayPadMain.java
index 4432218dad6cd31259783a0c8dc80af4e9fa473a..79b2b7b6aae33c837fff88e2546954a85186fb52 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/PlayPadMain.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/PlayPadMain.java
@@ -18,6 +18,7 @@ import de.tobias.playpad.profile.ref.ProfileReferenceManager;
 import de.tobias.playpad.project.Project;
 import de.tobias.playpad.project.ref.ProjectReferenceManager;
 import de.tobias.playpad.update.VersionUpdater;
+import de.tobias.playpad.util.ListSerializer;
 import de.tobias.playpad.util.UUIDSerializer;
 import de.tobias.playpad.viewcontroller.SplashScreenViewController;
 import io.github.openunirest.http.Unirest;
@@ -36,6 +37,7 @@ import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
 import java.util.UUID;
 
 /*
@@ -65,6 +67,7 @@ public class PlayPadMain extends Application {
 
 		// Register UserDefaults Serializer
 		UserDefaults.registerLoader(new UUIDSerializer(), UUID.class);
+		UserDefaults.registerLoader(new ListSerializer(), ArrayList.class);
 
 		ApplicationUtils.addAppListener(PlayPadMain::applicationWillStart);
 		App app = ApplicationUtils.registerMainApplication(PlayPadMain.class);
diff --git a/PlayWall/src/main/java/de/tobias/playpad/Strings.java b/PlayWall/src/main/java/de/tobias/playpad/Strings.java
index b28adcf21884f13366e14acc1b2f28b5a7ad0b00..e71f1944b156d2853018669b92e0ba6366fa9595 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/Strings.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/Strings.java
@@ -173,6 +173,7 @@ public class Strings {
 
 	// UI - Window - PadSettings
 	public static final String UI_WINDOW_PAD_SETTINGS_GENERAL_TITLE = "UI.Window.PadSettings.General.Title";
+	public static final String UI_WINDOW_PAD_SETTINGS_PLAYLIST_TITLE = "UI.Window.PadSettings.Playlist.Title";
 	public static final String UI_WINDOW_PAD_SETTINGS_PLAYER_TITLE = "UI.Window.PadSettings.Player.Title";
 	public static final String UI_WINDOW_PAD_SETTINGS_LAYOUT_TITLE = "UI.Window.PadSettings.Layout.Title";
 	public static final String UI_WINDOW_PAD_SETTINGS_TRIGGER_TITLE = "UI.Window.PadSettings.Trigger.Title";
diff --git a/PlayWall/src/main/java/de/tobias/playpad/design/ModernDesignAnimator.java b/PlayWall/src/main/java/de/tobias/playpad/design/ModernDesignAnimator.java
index d7ebadfc7f1e14ae7e77ffa5cad5ae4d618f71e5..ffd70e7b8b949a039aeb21718fdd335de4193f16 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/design/ModernDesignAnimator.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/design/ModernDesignAnimator.java
@@ -1,7 +1,7 @@
 package de.tobias.playpad.design;
 
 import de.tobias.playpad.pad.view.IPadView;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import de.tobias.playpad.util.FadeableColor;
 import de.tobias.playpad.view.PseudoClasses;
 import javafx.animation.KeyFrame;
@@ -23,7 +23,7 @@ public class ModernDesignAnimator {
 
 	private static HashMap<Integer, Timeline> timelines = new HashMap<>();
 
-	public static void animateFade(IPadViewController padViewController, FadeableColor startColor, FadeableColor endColor, Duration duration) {
+	public static void animateFade(AbstractPadViewController padViewController, FadeableColor startColor, FadeableColor endColor, Duration duration) {
 		ObjectProperty<FadeableColor> backgroundColor = new SimpleObjectProperty<>();
 
 		Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(0), new KeyValue(backgroundColor, startColor)),
@@ -32,7 +32,7 @@ public class ModernDesignAnimator {
 		animate(padViewController, timeline, backgroundColor);
 	}
 
-	public static void animateWarn(IPadViewController padViewController, FadeableColor startColor, FadeableColor endColor, Duration duration) {
+	public static void animateWarn(AbstractPadViewController padViewController, FadeableColor startColor, FadeableColor endColor, Duration duration) {
 		ObjectProperty<FadeableColor> backgroundColor = new SimpleObjectProperty<>();
 
 		Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(0), new KeyValue(backgroundColor, startColor)),
@@ -45,7 +45,7 @@ public class ModernDesignAnimator {
 		animate(padViewController, timeline, backgroundColor);
 	}
 
-	private static void animate(IPadViewController padViewController, Timeline timeline, ObjectProperty<FadeableColor> objectProperty) {
+	private static void animate(AbstractPadViewController padViewController, Timeline timeline, ObjectProperty<FadeableColor> objectProperty) {
 		int index = padViewController.getPad().getPosition();
 
 		if (timelines.containsKey(index)) {
@@ -68,7 +68,7 @@ public class ModernDesignAnimator {
 		timelines.put(index, timeline);
 	}
 
-	public static void stopAnimation(IPadViewController controller) {
+	public static void stopAnimation(AbstractPadViewController controller) {
 		int index = controller.getPad().getPosition();
 
 		if (timelines.containsKey(index)) {
@@ -76,7 +76,7 @@ public class ModernDesignAnimator {
 		}
 	}
 
-	public static void warnFlash(IPadViewController controller) {
+	public static void warnFlash(AbstractPadViewController controller) {
 		final IPadView view = controller.getView();
 		try {
 			while (!Thread.interrupted()) {
diff --git a/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/listener/PadNewContentListener.java b/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/listener/PadNewContentListener.java
index a2470391be71a7117f460051e78c274d269877e8..fedd12aea0879dbda04f8cc41b28c335c4807a8e 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/listener/PadNewContentListener.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/listener/PadNewContentListener.java
@@ -13,10 +13,12 @@ import de.tobias.playpad.settings.GlobalSettings;
 import javafx.event.ActionEvent;
 import javafx.scene.Node;
 import javafx.stage.FileChooser;
+import javafx.stage.Window;
 
 import java.io.File;
 import java.nio.file.Path;
-import java.util.Set;
+import java.util.Collections;
+import java.util.List;
 
 public class PadNewContentListener {
 
@@ -26,17 +28,14 @@ public class PadNewContentListener {
 		this.pad = pad;
 	}
 
-	public void onNew(ActionEvent event, PadContentFactory.PadContentTypeChooser padContentTypeChooser) throws NoSuchComponentException {
+	public List<File> showMediaOpenFileChooser(ActionEvent event, String[] supportedFileTypes, boolean multiSelect) {
 		GlobalSettings settings = PlayPadPlugin.getInstance().getGlobalSettings();
 		if (pad.getProject() != null && settings.isLiveMode() && settings.isLiveModeFile() && pad.getProject().getActivePlayers() > 0) {
-			return;
+			return Collections.emptyList();
 		}
 
 		final FileChooser chooser = new FileChooser();
-		PadContentRegistry registry = PlayPadPlugin.getRegistries().getPadContents();
-
-		// File Extension
-		final FileChooser.ExtensionFilter extensionFilter = new FileChooser.ExtensionFilter(Localization.getString(Strings.FILE_FILTER_MEDIA), registry.getSupportedFileTypes());
+		final FileChooser.ExtensionFilter extensionFilter = new FileChooser.ExtensionFilter(Localization.getString(Strings.FILE_FILTER_MEDIA), supportedFileTypes);
 		chooser.getExtensionFilters().add(extensionFilter);
 
 		// Last Folder
@@ -48,11 +47,28 @@ public class PadNewContentListener {
 			}
 		}
 
-		final File file = chooser.showOpenDialog(((Node) event.getTarget()).getScene().getWindow());
-		if (file != null) {
-			Path path = file.toPath();
+		final List<File> selectedFiles;
+		final Window window = ((Node) event.getTarget()).getScene().getWindow();
+		if (multiSelect) {
+			selectedFiles = chooser.showOpenMultipleDialog(window);
+		} else {
+			selectedFiles = Collections.singletonList(chooser.showOpenDialog(window));
+		}
+
+		if (selectedFiles != null && !selectedFiles.isEmpty()) {
+			ApplicationUtils.getApplication().getUserDefaults().setData(DesktopPadViewController.OPEN_FOLDER, selectedFiles.get(0).getParent());
+		}
+		return selectedFiles;
+	}
+
+	public void onNew(ActionEvent event, PadContentFactory.PadContentTypeChooser padContentTypeChooser) throws NoSuchComponentException {
+		final PadContentRegistry registry = PlayPadPlugin.getRegistries().getPadContents();
+		final List<File> files = showMediaOpenFileChooser(event, registry.getSupportedFileTypes(), false);
 
-			final Set<PadContentFactory> connects = registry.getPadContentConnectsForFile(file.toPath());
+		if (files != null) {
+			final Path path = files.get(0).toPath();
+
+			final List<PadContentFactory> connects = registry.getPadContentConnectsForFile(path);
 			if (!connects.isEmpty()) {
 				if (connects.size() > 1) { // Multiple content types possible
 					padContentTypeChooser.showOptions(connects, padContent ->
@@ -66,8 +82,6 @@ public class PadNewContentListener {
 					setNewPadContent(path, padContent);
 				}
 			}
-
-			ApplicationUtils.getApplication().getUserDefaults().setData(DesktopPadViewController.OPEN_FOLDER, path.getParent().toString());
 		}
 	}
 
diff --git a/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadDragListener.java b/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadDragListener.java
index 637686246100491b6b093d6fd525637741fcd489..fff46f264a0632184ab597a851d5eba90fcf7b47 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadDragListener.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadDragListener.java
@@ -7,7 +7,10 @@ import de.tobias.playpad.pad.Pad;
 import de.tobias.playpad.pad.PadStatus;
 import de.tobias.playpad.pad.content.PadContentFactory;
 import de.tobias.playpad.pad.content.PadContentRegistry;
+import de.tobias.playpad.pad.content.Playlistable;
+import de.tobias.playpad.pad.drag.ContentDragOption;
 import de.tobias.playpad.pad.drag.PadDragMode;
+import de.tobias.playpad.pad.drag.PlaylistDragOption;
 import de.tobias.playpad.pad.view.IPadView;
 import de.tobias.playpad.profile.Profile;
 import de.tobias.playpad.project.Project;
@@ -26,18 +29,21 @@ import javafx.scene.layout.Pane;
 import javafx.scene.paint.Color;
 
 import java.io.File;
+import java.nio.file.Path;
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Set;
+import java.util.List;
+import java.util.stream.Collectors;
 
 public class DesktopPadDragListener implements EventHandler<DragEvent> {
 
-	private static final String PADINDEX_DATATYPE = "de.tobias.playpad.padindex";
-	private static final DataFormat dataFormat = new DataFormat(PADINDEX_DATATYPE);
+	private static final String PAD_INDEX_DATATYPE = "de.tobias.playpad.pad_index";
+	private static final DataFormat dataFormat = new DataFormat(PAD_INDEX_DATATYPE);
 
-	private Pad currentPad;
-	private final Pane padView; // Node der PadView
+	private final Pad currentPad;
+	private final Pane padViewNode; // Node der PadView
 
-	private DesktopMainLayoutFactory connect;
+	private final DesktopMainLayoutFactory connect;
 
 	private PadDragOptionView padHud;
 	private FileDragOptionView fileHud;
@@ -46,21 +52,21 @@ public class DesktopPadDragListener implements EventHandler<DragEvent> {
 		this.currentPad = currentPad;
 		this.connect = connect;
 
-		this.padView = view.getRootNode();
+		this.padViewNode = view.getRootNode();
 	}
 
 	public void addListener() {
-		this.padView.setOnDragOver(this::dragOver);
-		this.padView.setOnDragExited(event -> dragExited());
-		this.padView.setOnDragDropped(this::dragDropped);
-		this.padView.setOnDragDetected(this::dragDetacted);
+		this.padViewNode.setOnDragOver(this::dragOver);
+		this.padViewNode.setOnDragExited(event -> dragExited());
+		this.padViewNode.setOnDragDropped(this::dragDropped);
+		this.padViewNode.setOnDragDetected(this::dragDetected);
 	}
 
 	void removeListener() {
-		this.padView.setOnDragOver(null);
-		this.padView.setOnDragExited(null);
-		this.padView.setOnDragDropped(null);
-		this.padView.setOnDragDetected(null);
+		this.padViewNode.setOnDragOver(null);
+		this.padViewNode.setOnDragExited(null);
+		this.padViewNode.setOnDragDropped(null);
+		this.padViewNode.setOnDragDetected(null);
 	}
 
 	@Override
@@ -75,52 +81,67 @@ public class DesktopPadDragListener implements EventHandler<DragEvent> {
 	}
 
 	private void dragOver(DragEvent event) {
-		if (Profile.currentProfile().getProfileSettings().isLocked()) {
+		if (Profile.currentProfile().getProfileSettings().isLocked() || checkLiveMode()) {
 			return;
 		}
 
 		if (event.getGestureSource() != this && event.getDragboard().hasFiles()) {
-			File file = event.getDragboard().getFiles().get(0);
-			if (file.isFile()) {
-				// Check Live Mode
-				if (checkLiveMode()) {
-					return;
-				}
+			handleFileDropOver(event);
+		} else if (event.getDragboard().hasContent(dataFormat)) {
+			handlePadDragOver(event);
+		}
+		event.consume();
+	}
+
+	@SuppressWarnings("java:S1066")
+	private void handleFileDropOver(DragEvent event) {
+		final File file = event.getDragboard().getFiles().get(0);
+		if (file.isFile()) {
 
-				// Build In Filesupport
-				PadContentRegistry registry = PlayPadPlugin.getRegistries().getPadContents();
-				Set<PadContentFactory> connects = registry.getPadContentConnectsForFile(file.toPath());
+			final List<Path> paths = event.getDragboard().getFiles().stream().map(File::toPath).collect(Collectors.toList());
 
-				if (!connects.isEmpty()) {
-					if (fileHud == null) {
-						fileHud = new FileDragOptionView(padView);
-					}
-					fileHud.showOptions(connects);
+			// built-in file support
+			final PadContentRegistry registry = PlayPadPlugin.getRegistries().getPadContents();
+			final List<PadContentFactory> supportedContentTypes = registry.getPadContentConnectsForFiles(paths);
 
-					event.acceptTransferModes(TransferMode.LINK);
-					return;
+			if (currentPad.getContent() != null && currentPad.getContent().isPadLoading()) {
+				return;
+			}
+
+			final List<ContentDragOption> contentDragOptions = new ArrayList<>(supportedContentTypes);
+
+			if (currentPad.getContent() instanceof Playlistable) {
+				if (supportedContentTypes.stream().anyMatch(factory -> factory.getType().equals(currentPad.getContent().getType()))) {
+					contentDragOptions.add(new PlaylistDragOption());
 				}
 			}
-		}
 
-		// Drag and Drop von Pads
-		if (event.getDragboard().hasContent(dataFormat)) {
-			PadIndex index = (PadIndex) event.getDragboard().getContent(dataFormat);
-			if (!currentPad.getPadIndex().equals(index)) {
+			if (!contentDragOptions.isEmpty()) {
+				if (fileHud == null) {
+					fileHud = new FileDragOptionView(padViewNode);
+				}
+				fileHud.showOptions(contentDragOptions);
+
+				event.acceptTransferModes(TransferMode.LINK);
+			}
+		}
+	}
 
-				Collection<PadDragMode> connects = PlayPadPlugin.getRegistries().getDragModes().getComponents();
+	private void handlePadDragOver(DragEvent event) {
+		PadIndex index = (PadIndex) event.getDragboard().getContent(dataFormat);
+		if (!currentPad.getPadIndex().equals(index)) {
 
-				if (!connects.isEmpty()) {
-					if (padHud == null) {
-						padHud = new PadDragOptionView(padView);
-					}
-					padHud.showDropOptions(connects);
+			Collection<PadDragMode> connects = PlayPadPlugin.getRegistries().getDragModes().getComponents();
 
-					event.acceptTransferModes(TransferMode.MOVE);
+			if (!connects.isEmpty()) {
+				if (padHud == null) {
+					padHud = new PadDragOptionView(padViewNode);
 				}
+				padHud.showDropOptions(connects);
+
+				event.acceptTransferModes(TransferMode.MOVE);
 			}
 		}
-		event.consume();
 	}
 
 	private void dragExited() {
@@ -134,79 +155,83 @@ public class DesktopPadDragListener implements EventHandler<DragEvent> {
 
 	// Drag Content ist los gelassen am Ziel
 	private void dragDropped(DragEvent event) {
-		Project project = PlayPadPlugin.getInstance().getCurrentProject();
+		final Project project = PlayPadPlugin.getInstance().getCurrentProject();
 
-		Dragboard db = event.getDragboard();
+		final Dragboard dragboard = event.getDragboard();
 		boolean success = false;
 
 		// File Handling
-		if (db.hasFiles()) {
-			File file = db.getFiles().get(0);
-
-			PadContentFactory connect = fileHud.getSelectedConnect();
-			if (connect != null) {
-				// stop pad if playing
-				if(currentPad.getContent() != null && currentPad.getStatus().equals(PadStatus.PLAY)) {
-					currentPad.getContent().stop();
-					currentPad.stop();
-				}
+		if (dragboard.hasFiles()) {
+			success = handleFileDragDropped(dragboard);
+		}
 
-				if (currentPad.getContent() == null || !currentPad.getContent().getType().equals(connect.getType())) {
-					currentPad.setContentType(connect.getType());
-				}
+		// Pad DnD
+		if (dragboard.hasContent(dataFormat)) {
+			success = handlePadDragDropped(project, dragboard);
+		}
+		// Event Completion
+		event.setDropCompleted(success);
+		event.consume();
+	}
 
-				if (currentPad.isPadVisible()) {
-					currentPad.getController().getView().showBusyView(true);
-				}
+	private boolean handleFileDragDropped(Dragboard dragboard) {
+		final ContentDragOption dragOption = fileHud.getSelectedConnect();
+		if (dragOption != null) {
+			// stop pad if playing
+			if (currentPad.getContent() != null && currentPad.getStatus().equals(PadStatus.PLAY)) {
+				currentPad.getContent().stop();
+				currentPad.stop();
+			}
 
-				this.currentPad.setPath(file.toPath());
+			dragOption.handleDrop(currentPad, dragboard.getFiles());
 
-				if (currentPad.getController() != null) {
-					IPadView padView = currentPad.getController().getView();
-					padView.setContentView(currentPad);
-					padView.addDefaultElements(currentPad);
-				}
+			if (currentPad.getController() != null) {
+				final IPadView padView = currentPad.getController().getView();
+				padView.setContentView(currentPad);
+				padView.addDefaultElements(currentPad);
 			}
+
+			return true;
 		}
+		return false;
+	}
 
-		// Pad DnD
-		if (db.hasContent(dataFormat)) {
-			Object data = db.getContent(dataFormat);
-			if (data instanceof PadIndex) {
-				PadIndex srcIndex = (PadIndex) data;
-				PadIndex newIndex = currentPad.getPadIndex(); // Lister ist auf Ziel Pad, daher ist der Index von currentPad
-
-				// Drag handle
-				PadDragMode mode = padHud.getSelectedPadDragMode();
-				success = mode.handle(srcIndex, newIndex, project);
-				padHud.hide();
-
-				// Update der Pad Views nach dem DnD
-				IMainViewController mainViewController = PlayPadPlugin.getInstance().getMainViewController();
-				mainViewController.showPage(mainViewController.getPage());
-
-				if (project.getProjectReference().isSync()) {
-					CommandManager.execute(Commands.PAD_MOVE);
-				}
+	private boolean handlePadDragDropped(Project project, Dragboard dragboard) {
+		boolean success = false;
+
+		Object data = dragboard.getContent(dataFormat);
+		if (data instanceof PadIndex) {
+			PadIndex srcIndex = (PadIndex) data;
+			PadIndex newIndex = currentPad.getPadIndex(); // Lister ist auf Ziel Pad, daher ist der Index von currentPad
+
+			// Drag handle
+			PadDragMode mode = padHud.getSelectedPadDragMode();
+			success = mode.handle(srcIndex, newIndex, project);
+			padHud.hide();
+
+			// Update der Pad Views nach dem DnD
+			IMainViewController mainViewController = PlayPadPlugin.getInstance().getMainViewController();
+			mainViewController.showPage(mainViewController.getPage());
+
+			if (project.getProjectReference().isSync()) {
+				CommandManager.execute(Commands.PAD_MOVE);
 			}
 		}
-		// Event Completion
-		event.setDropCompleted(success);
-		event.consume();
+		return success;
 	}
 
-	private void dragDetacted(MouseEvent event) {
+	private void dragDetected(MouseEvent event) {
 		if (connect.getEditMode() == DesktopEditMode.DRAG) {
 			if (checkLiveMode()) {
 				return;
 			}
 
-			Dragboard dragboard = padView.startDragAndDrop(TransferMode.MOVE);
+			Dragboard dragboard = padViewNode.startDragAndDrop(TransferMode.MOVE);
 
 			// Create Snapshot
 			SnapshotParameters parameters = new SnapshotParameters();
 			parameters.setFill(Color.TRANSPARENT);
-			WritableImage snapshot = padView.snapshot(parameters, null);
+			WritableImage snapshot = padViewNode.snapshot(parameters, null);
 			for (int x = 0; x < snapshot.getWidth(); x++) {
 				for (int y = 0; y < snapshot.getHeight(); y++) {
 					Color oldColor = snapshot.getPixelReader().getColor(x, y).darker().darker();
@@ -229,9 +254,7 @@ public class DesktopPadDragListener implements EventHandler<DragEvent> {
 	private boolean checkLiveMode() {
 		GlobalSettings globalSettings = PlayPadPlugin.getInstance().getGlobalSettings();
 		if (currentPad.getProject() != null) {
-			if (globalSettings.isLiveMode() && globalSettings.isLiveModeFile() && currentPad.getProject().getActivePlayers() > 0) {
-				return true;
-			}
+			return globalSettings.isLiveMode() && globalSettings.isLiveModeFile() && currentPad.getProject().getActivePlayers() > 0;
 		}
 		return false;
 	}
diff --git a/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadView.java b/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadView.java
index 1f22e8a009f5d727ee47fbb9a57377ebe1631963..e1489f3445343db9ef7b1b3a46be0e6030a8f690 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadView.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadView.java
@@ -14,10 +14,11 @@ import de.tobias.playpad.pad.PadStatus;
 import de.tobias.playpad.pad.content.PadContent;
 import de.tobias.playpad.pad.content.PadContentFactory;
 import de.tobias.playpad.pad.content.PadContentRegistry;
+import de.tobias.playpad.pad.content.Playlistable;
 import de.tobias.playpad.pad.content.play.Pauseable;
 import de.tobias.playpad.pad.view.IPadContentView;
 import de.tobias.playpad.pad.view.IPadView;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import de.tobias.playpad.profile.Profile;
 import de.tobias.playpad.project.page.PadIndex;
 import de.tobias.playpad.registry.NoSuchComponentException;
@@ -29,6 +30,7 @@ import javafx.beans.property.Property;
 import javafx.css.PseudoClass;
 import javafx.geometry.Pos;
 import javafx.scene.Node;
+import javafx.scene.Parent;
 import javafx.scene.control.Button;
 import javafx.scene.control.Label;
 import javafx.scene.control.ProgressBar;
@@ -42,6 +44,7 @@ public class DesktopPadView implements IPadView {
 	private Label indexLabel;
 	private Label loopLabel;
 	private Label triggerLabel;
+	private Label playlistLabel;
 	private Label errorLabel;
 
 	private HBox infoBox;
@@ -55,6 +58,7 @@ public class DesktopPadView implements IPadView {
 	private ProgressBar playBar;
 	private Button playButton;
 	private Button pauseButton;
+	private Button nextButton;
 	private Button stopButton;
 	private Button newButton;
 	private Button settingsButton;
@@ -88,6 +92,7 @@ public class DesktopPadView implements IPadView {
 
 		loopLabel = new PadLabel(new FontIcon(FontAwesomeType.REPEAT));
 		triggerLabel = new PadLabel(new FontIcon(FontAwesomeType.EXTERNAL_LINK));
+		playlistLabel = PadLabel.empty(STYLE_CLASS_PAD_INFO, STYLE_CLASS_PAD_INFO_INDEX);
 		errorLabel = new PadLabel(new FontIcon(FontAwesomeType.WARNING));
 
 		infoBox = new PadHBox(5);
@@ -106,6 +111,7 @@ public class DesktopPadView implements IPadView {
 		// Buttons
 		playButton = new PadButton(new FontIcon(FontAwesomeType.PLAY), controller);
 		pauseButton = new PadButton(new FontIcon(FontAwesomeType.PAUSE), controller);
+		nextButton = new PadButton(new FontIcon(FontAwesomeType.STEP_FORWARD), controller);
 		stopButton = new PadButton(new FontIcon(FontAwesomeType.STOP), controller);
 		newButton = new PadButton(new FontIcon(FontAwesomeType.FOLDER_OPEN), controller);
 		settingsButton = new PadButton(new FontIcon(FontAwesomeType.GEAR), controller);
@@ -146,11 +152,11 @@ public class DesktopPadView implements IPadView {
 					PadContentFactory connect = registry.getFactory(content.getType());
 
 					previewContent = connect.getPadContentPreview(pad, preview);
-					Node node = previewContent.getNode();
+					Parent node = previewContent.getNode();
 
-					// Copy Pseudoclasses
+					// Copy Pseudo classes
 					for (PseudoClass pseudoClass : superRoot.getPseudoClassStates()) {
-						node.pseudoClassStateChanged(pseudoClass, true);
+						NodeWalker.getAllNodes(node).forEach(element -> element.pseudoClassStateChanged(pseudoClass, true));
 					}
 
 					preview.getChildren().setAll(node);
@@ -165,7 +171,7 @@ public class DesktopPadView implements IPadView {
 	}
 
 	@Override
-	public IPadViewController getViewController() {
+	public AbstractPadViewController getViewController() {
 		return controller;
 	}
 
@@ -212,6 +218,10 @@ public class DesktopPadView implements IPadView {
 		return pauseButton;
 	}
 
+	Button getNextButton() {
+		return nextButton;
+	}
+
 	Button getStopButton() {
 		return stopButton;
 	}
@@ -250,7 +260,11 @@ public class DesktopPadView implements IPadView {
 			if (pad.getContent() != null) {
 				if (pad.getContent() instanceof Pauseable) {
 					if (pad.getStatus() == PadStatus.PLAY) {
-						buttonBox.getChildren().setAll(pauseButton, stopButton, settingsButton);
+						if (pad.getContent() instanceof Playlistable) {
+							buttonBox.getChildren().setAll(pauseButton, nextButton, stopButton, settingsButton);
+						} else {
+							buttonBox.getChildren().setAll(pauseButton, stopButton, settingsButton);
+						}
 					} else {
 						buttonBox.getChildren().setAll(playButton, stopButton, settingsButton);
 					}
@@ -262,7 +276,7 @@ public class DesktopPadView implements IPadView {
 			}
 			applyStyleClasses(pad.getPadIndex());
 		}
-		infoBox.getChildren().setAll(indexLabel, loopLabel, triggerLabel, errorLabel, timeLabel);
+		infoBox.getChildren().setAll(indexLabel, loopLabel, triggerLabel, playlistLabel, errorLabel, timeLabel);
 
 		// Buttons unten Full Width
 		buttonBox.prefWidthProperty().bind(superRoot.widthProperty());
@@ -318,6 +332,10 @@ public class DesktopPadView implements IPadView {
 		setContentView(null);
 	}
 
+	public Label getPlaylistLabel() {
+		return playlistLabel;
+	}
+
 	@Override
 	public void setPlaybarVisible(boolean visible) {
 		playBar.setVisible(visible);
diff --git a/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadViewController.java b/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadViewController.java
index 9da5a3879097a79a71b00405ef39fd4d7a9df3ae..fd9acc77f4555699721cdea533a759b8a673a3fd 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadViewController.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/layout/desktop/pad/DesktopPadViewController.java
@@ -9,10 +9,11 @@ import de.tobias.playpad.layout.desktop.listener.PadNewContentListener;
 import de.tobias.playpad.pad.Pad;
 import de.tobias.playpad.pad.PadStatus;
 import de.tobias.playpad.pad.TimeMode;
+import de.tobias.playpad.pad.content.Playlistable;
 import de.tobias.playpad.pad.content.play.Durationable;
 import de.tobias.playpad.pad.listener.*;
 import de.tobias.playpad.pad.view.IPadView;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import de.tobias.playpad.profile.Profile;
 import de.tobias.playpad.profile.ProfileSettings;
 import de.tobias.playpad.registry.NoSuchComponentException;
@@ -23,22 +24,21 @@ import de.tobias.playpad.viewcontroller.option.pad.PadSettingsViewController;
 import javafx.beans.value.ChangeListener;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
-import javafx.stage.Stage;
 import javafx.util.Duration;
 
-public class DesktopPadViewController implements IPadViewController, EventHandler<ActionEvent> {
+public class DesktopPadViewController extends AbstractPadViewController implements EventHandler<ActionEvent> {
 
 	public static final String OPEN_FOLDER = "openFolder";
 	private static final String DURATION_FORMAT = "%d:%02d";
 
-	private DesktopPadView padView;
+	private final DesktopPadView padView;
 	private Pad pad;
 
-	private PadLockedListener padLockedListener;
-	private PadStatusListener padStatusListener;
-	private PadContentListener padContentListener;
-	private PadDurationListener padDurationListener;
-	private IPadPositionListener padPositionListener;
+	private final PadLockedListener padLockedListener;
+	private final PadStatusListener padStatusListener;
+	private final PadContentListener padContentListener;
+	private final PadDurationListener padDurationListener;
+	private final IPadPositionListener padPositionListener;
 
 	private DesktopPadDragListener padDragListener;
 
@@ -84,6 +84,8 @@ public class DesktopPadViewController implements IPadViewController, EventHandle
 			padView.loopLabelVisibleProperty().bind(pad.getPadSettings().loopProperty());
 			padView.setTriggerLabelActive(pad.getPadSettings().hasTriggerItems());
 
+			updatePlaylistLabelBinding(pad);
+
 			// Update Listener
 			padContentListener.setPad(pad);
 			padPositionListener.setPad(pad);
@@ -94,7 +96,7 @@ public class DesktopPadViewController implements IPadViewController, EventHandle
 
 			// Initial Listener call with new data
 			padContentListener.changed(null, null, pad.getContent()); // Add Duration listener
-			padStatusListener.changed(null, null, pad.getStatus());
+			padStatusListener.changed(null, null, pad.getStatus()); // Show correct pseudo classes ...
 
 			// Add Drag and Drop Listener
 			padDragListener = new DesktopPadDragListener(pad, padView, connect);
@@ -117,6 +119,9 @@ public class DesktopPadViewController implements IPadViewController, EventHandle
 			padView.setTriggerLabelActive(false);
 			padView.loopLabelVisibleProperty().unbind();
 
+			padView.getPlaylistLabel().textProperty().unbind();
+			padView.getPlaylistLabel().setText("");
+
 			// Remove Bindings & Listener
 			pad.contentProperty().removeListener(padContentListener);
 			pad.statusProperty().removeListener(padStatusListener);
@@ -152,6 +157,8 @@ public class DesktopPadViewController implements IPadViewController, EventHandle
 				onPlay();
 			} else if (event.getSource() == padView.getPauseButton()) {
 				onPause();
+			} else if (event.getSource() == padView.getNextButton()) {
+				onNext();
 			} else if (event.getSource() == padView.getStopButton()) {
 				onStop();
 			} else if (event.getSource() == padView.getNewButton()) {
@@ -179,6 +186,12 @@ public class DesktopPadViewController implements IPadViewController, EventHandle
 		}
 	}
 
+	private void onNext() {
+		if (pad.getContent() instanceof Playlistable) {
+			((Playlistable) pad.getContent()).next();
+		}
+	}
+
 	private void onStop() {
 		if (pad.getContent() != null) {
 			pad.setStatus(PadStatus.STOP);
@@ -195,15 +208,11 @@ public class DesktopPadViewController implements IPadViewController, EventHandle
 		IMainViewController mvc = PlayPadPlugin.getInstance().getMainViewController();
 
 		if (mvc != null) {
-			if (pad.getProject() != null) {
-				if (settings.isLiveMode() && settings.isLiveModeSettings() && pad.getProject().getActivePlayers() > 0) {
-					return;
-				}
+			if (pad.getProject() != null && settings.isLiveMode() && settings.isLiveModeSettings() && pad.getProject().getActivePlayers() > 0) {
+				return;
 			}
 
-			Stage owner = mvc.getStage();
-
-			PadSettingsViewController padSettingsViewController = new PadSettingsViewController(pad, owner);
+			PadSettingsViewController padSettingsViewController = new PadSettingsViewController(pad, mvc);
 			padSettingsViewController.getStageContainer().ifPresent(nvcStage -> nvcStage.addCloseHook(() -> {
 				if (padView != null && pad != null)
 					padView.setTriggerLabelActive(pad.getPadSettings().hasTriggerItems());
diff --git a/PlayWall/src/main/java/de/tobias/playpad/layout/touch/pad/TouchPadView.java b/PlayWall/src/main/java/de/tobias/playpad/layout/touch/pad/TouchPadView.java
index 0ae8de45f92ab9a27cbeb1c642ad083763efbc9d..3c220b8ba255b641ea8355d2cc818418e90e1a5f 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/layout/touch/pad/TouchPadView.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/layout/touch/pad/TouchPadView.java
@@ -14,7 +14,7 @@ import de.tobias.playpad.pad.content.PadContent;
 import de.tobias.playpad.pad.content.PadContentFactory;
 import de.tobias.playpad.pad.view.IPadContentView;
 import de.tobias.playpad.pad.view.IPadView;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import de.tobias.playpad.profile.Profile;
 import de.tobias.playpad.project.page.PadIndex;
 import de.tobias.playpad.registry.NoSuchComponentException;
@@ -38,6 +38,7 @@ public class TouchPadView implements IPadView {
 	private Label indexLabel;
 	private Label loopLabel;
 	private Label triggerLabel;
+	private Label playlistLabel;
 	private Label errorLabel;
 
 	private HBox infoBox;
@@ -77,6 +78,7 @@ public class TouchPadView implements IPadView {
 
 		loopLabel = new PadLabel(new FontIcon(FontAwesomeType.REPEAT));
 		triggerLabel = new PadLabel(new FontIcon(FontAwesomeType.EXTERNAL_LINK));
+		playlistLabel = PadLabel.empty(STYLE_CLASS_PAD_INFO, STYLE_CLASS_PAD_INFO_INDEX);
 		errorLabel = new PadLabel(new FontIcon(FontAwesomeType.WARNING));
 
 		infoBox = new PadHBox(5);
@@ -147,7 +149,7 @@ public class TouchPadView implements IPadView {
 	}
 
 	@Override
-	public IPadViewController getViewController() {
+	public AbstractPadViewController getViewController() {
 		return controller;
 	}
 
@@ -212,7 +214,7 @@ public class TouchPadView implements IPadView {
 
 	@Override
 	public void addDefaultElements(Pad pad) {
-		infoBox.getChildren().setAll(indexLabel, loopLabel, triggerLabel, errorLabel, timeLabel);
+		infoBox.getChildren().setAll(indexLabel, loopLabel, triggerLabel, playlistLabel, errorLabel, timeLabel);
 
 		// alle Labels in der InfoBox sollen die gleiche Höhe haben, damit die Icons auf gleicher höhe sind
 		for (Node child : infoBox.getChildren()) {
@@ -258,6 +260,10 @@ public class TouchPadView implements IPadView {
 		setContentView(null);
 	}
 
+	public Label getPlaylistLabel() {
+		return playlistLabel;
+	}
+
 	@Override
 	public void setPlaybarVisible(boolean visible) {
 		playBar.setVisible(visible);
diff --git a/PlayWall/src/main/java/de/tobias/playpad/layout/touch/pad/TouchPadViewController.java b/PlayWall/src/main/java/de/tobias/playpad/layout/touch/pad/TouchPadViewController.java
index d6a75430cb0063cd1191e25e9a2499c2f7080f92..c43b9679075c400a0e949b80e2b9ab64e28d4f50 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/layout/touch/pad/TouchPadViewController.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/layout/touch/pad/TouchPadViewController.java
@@ -7,7 +7,7 @@ import de.tobias.playpad.pad.TimeMode;
 import de.tobias.playpad.pad.content.play.Durationable;
 import de.tobias.playpad.pad.listener.*;
 import de.tobias.playpad.pad.view.IPadView;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import de.tobias.playpad.profile.Profile;
 import de.tobias.playpad.profile.ProfileSettings;
 import javafx.beans.value.ChangeListener;
@@ -18,7 +18,7 @@ import javafx.scene.input.MouseEvent;
 import javafx.scene.input.TouchEvent;
 import javafx.util.Duration;
 
-public class TouchPadViewController implements IPadViewController, EventHandler<Event> {
+public class TouchPadViewController extends AbstractPadViewController implements EventHandler<Event> {
 
 	protected static final String CURRENT_PAGE_BUTTON = "current-page-button";
 	private static final String DURATION_FORMAT = "%d:%02d";
@@ -70,11 +70,13 @@ public class TouchPadViewController implements IPadViewController, EventHandler<
 			padView.loopLabelVisibleProperty().bind(pad.getPadSettings().loopProperty());
 			padView.setTriggerLabelActive(pad.getPadSettings().hasTriggerItems());
 
+			updatePlaylistLabelBinding(pad);
+
 			// Update Listener
 			padContentListener.setPad(pad);
 			padPositionListener.setPad(pad);
 
-			// Pad Content Chnage
+			// Pad Content Change
 			pad.contentProperty().addListener(padContentListener);
 			// Pad Status Change
 			pad.statusProperty().addListener(padStatusListener);
@@ -98,6 +100,9 @@ public class TouchPadViewController implements IPadViewController, EventHandler<
 			padView.clearPreviewContent();
 			padView.clearTime();
 
+			padView.getPlaylistLabel().textProperty().unbind();
+			padView.getPlaylistLabel().setText("");
+
 			padView.setTriggerLabelActive(false);
 
 			padView.loopLabelVisibleProperty().unbind();
diff --git a/PlayWall/src/main/java/de/tobias/playpad/pad/content/AudioPadContentFactory.java b/PlayWall/src/main/java/de/tobias/playpad/pad/content/AudioPadContentFactory.java
index d60a59d949a82adbb94f117600f4d9e6fd95da51..8e5f4339e3e2107bab28ee4ba9c591fcabe1c138 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/pad/content/AudioPadContentFactory.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/pad/content/AudioPadContentFactory.java
@@ -1,16 +1,11 @@
 package de.tobias.playpad.pad.content;
 
 import de.tobias.playpad.pad.Pad;
+import de.tobias.playpad.pad.preview.PadTextPreview;
 import de.tobias.playpad.pad.view.IPadContentView;
 import de.tobias.playpad.viewcontroller.option.ProfileSettingsTabViewController;
 import de.tobias.playpad.viewcontroller.option.profile.AudioTabViewController;
-import javafx.geometry.Pos;
-import javafx.scene.Node;
-import javafx.scene.control.Label;
 import javafx.scene.layout.Pane;
-import javafx.scene.layout.Priority;
-import javafx.scene.layout.VBox;
-import javafx.scene.text.TextAlignment;
 
 public class AudioPadContentFactory extends PadContentFactory {
 
@@ -33,7 +28,7 @@ public class AudioPadContentFactory extends PadContentFactory {
 	@Override
 	public IPadContentView getPadContentPreview(Pad pad, Pane parentNode) {
 		if (pad.getContent() != null) {
-			return new AudioContentView(pad, parentNode);
+			return new PadTextPreview(pad, parentNode);
 		} else {
 			return null;
 		}
@@ -43,32 +38,4 @@ public class AudioPadContentFactory extends PadContentFactory {
 	public ProfileSettingsTabViewController getSettingsTabViewController(boolean activePlayer) {
 		return new AudioTabViewController(activePlayer);
 	}
-
-	private static class AudioContentView implements IPadContentView {
-
-		private Label nameLabel;
-
-		AudioContentView(Pad pad, Pane parentNode) {
-			nameLabel = new Label();
-			nameLabel.textProperty().bind(pad.nameProperty());
-
-			nameLabel.setWrapText(true);
-			nameLabel.setAlignment(Pos.CENTER);
-			nameLabel.setTextAlignment(TextAlignment.CENTER);
-
-			nameLabel.prefWidthProperty().bind(parentNode.widthProperty());
-			nameLabel.setMaxHeight(Double.MAX_VALUE);
-			VBox.setVgrow(nameLabel, Priority.ALWAYS);
-		}
-
-		@Override
-		public Node getNode() {
-			return nameLabel;
-		}
-
-		@Override
-		public void deInit() {
-			nameLabel.textProperty().unbind();
-		}
-	}
 }
diff --git a/PlayWall/src/main/java/de/tobias/playpad/pad/drag/PlaylistDragOption.java b/PlayWall/src/main/java/de/tobias/playpad/pad/drag/PlaylistDragOption.java
new file mode 100644
index 0000000000000000000000000000000000000000..69e86ec2c6f8c2b9c437daffec996dc9aea8213a
--- /dev/null
+++ b/PlayWall/src/main/java/de/tobias/playpad/pad/drag/PlaylistDragOption.java
@@ -0,0 +1,40 @@
+package de.tobias.playpad.pad.drag;
+
+import de.thecodelabs.utils.ui.icon.FontAwesomeType;
+import de.thecodelabs.utils.ui.icon.FontIcon;
+import de.thecodelabs.utils.util.Localization;
+import de.tobias.playpad.pad.Pad;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.property.StringProperty;
+import javafx.scene.Node;
+
+import java.io.File;
+import java.util.List;
+
+public class PlaylistDragOption implements ContentDragOption {
+
+	private final StringProperty displayProperty = new SimpleStringProperty(Localization.getString("DndMode.Playlist"));
+
+	@Override
+	public void handleDrop(Pad currentPad, List<File> files) {
+		if (currentPad.isPadVisible()) {
+			currentPad.getController().getView().showBusyView(true);
+		}
+
+		for (File file : files) {
+			currentPad.addPath(file.toPath());
+		}
+	}
+
+	@Override
+	public StringProperty displayProperty() {
+		return displayProperty;
+	}
+
+	@Override
+	public Node getGraphics() {
+		final FontIcon fontIcon = new FontIcon(FontAwesomeType.PLUS_CIRCLE);
+		fontIcon.setSize(30);
+		return fontIcon;
+	}
+}
diff --git a/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadContentListener.java b/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadContentListener.java
index 0b88a71ca642f337b7c892cf68bc04d3a2efc9ab..20c58f70592345eadb08fc634bcf34a7824951ec 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadContentListener.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadContentListener.java
@@ -3,16 +3,16 @@ package de.tobias.playpad.pad.listener;
 import de.tobias.playpad.pad.Pad;
 import de.tobias.playpad.pad.content.PadContent;
 import de.tobias.playpad.pad.content.play.Durationable;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 
 public class PadContentListener implements ChangeListener<PadContent> {
 
 	private Pad pad;
-	private IPadViewController controller;
+	private final AbstractPadViewController controller;
 
-	public PadContentListener(IPadViewController controller) {
+	public PadContentListener(AbstractPadViewController controller) {
 		this.controller = controller;
 	}
 
@@ -49,5 +49,7 @@ public class PadContentListener implements ChangeListener<PadContent> {
 		} else {
 			controller.getView().setPlaybarVisible(false);
 		}
+
+		controller.updatePlaylistLabelBinding(pad);
 	}
 }
diff --git a/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadDurationListener.java b/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadDurationListener.java
index ce208522f99ec464cbe6996109ad0a4b3c9210d5..a364fed1a5f5f6996c4885374d1b8acd70faa936 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadDurationListener.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadDurationListener.java
@@ -1,15 +1,15 @@
 package de.tobias.playpad.pad.listener;
 
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 import javafx.util.Duration;
 
 public class PadDurationListener implements ChangeListener<Duration> {
 
-	private IPadViewController controller;
+	private AbstractPadViewController controller;
 
-	public PadDurationListener(IPadViewController controller) {
+	public PadDurationListener(AbstractPadViewController controller) {
 		this.controller = controller;
 	}
 
diff --git a/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadLockedListener.java b/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadLockedListener.java
index 702951b06dab11e634e5c4aec827a06c98638f4e..e94995dda657050904571c0d88dec486b4d62dfa 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadLockedListener.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadLockedListener.java
@@ -1,14 +1,14 @@
 package de.tobias.playpad.pad.listener;
 
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 
 public class PadLockedListener implements ChangeListener<Boolean> {
 
-	private IPadViewController controller;
+	private AbstractPadViewController controller;
 
-	public PadLockedListener(IPadViewController controller) {
+	public PadLockedListener(AbstractPadViewController controller) {
 		this.controller = controller;
 	}
 
diff --git a/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadPositionListener.java b/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadPositionListener.java
index 579fe5a9dfb6fbac7a207b2f67b09cfce5c74800..5326b5f914229d7a4e1b9499bb44c01234d00ecf 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadPositionListener.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadPositionListener.java
@@ -13,7 +13,7 @@ import de.tobias.playpad.pad.PadStatus;
 import de.tobias.playpad.pad.content.PadContent;
 import de.tobias.playpad.pad.content.play.Durationable;
 import de.tobias.playpad.pad.fade.Fadeable;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import de.tobias.playpad.profile.Profile;
 import javafx.beans.value.ObservableValue;
 import javafx.util.Duration;
@@ -21,9 +21,9 @@ import javafx.util.Duration;
 public class PadPositionListener implements Runnable, IPadPositionListener {
 
 	private Pad pad;
-	private IPadViewController controller;
+	private AbstractPadViewController controller;
 
-	public PadPositionListener(IPadViewController controller) {
+	public PadPositionListener(AbstractPadViewController controller) {
 		this.controller = controller;
 	}
 
diff --git a/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadStatusListener.java b/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadStatusListener.java
index bda5270de706c8c4ecfece808faaa2780eb11170..061cc894962680419298d76f8b326c825afb6770 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadStatusListener.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/pad/listener/PadStatusListener.java
@@ -3,16 +3,16 @@ package de.tobias.playpad.pad.listener;
 import de.thecodelabs.midi.Mapping;
 import de.tobias.playpad.action.actions.CartAction;
 import de.tobias.playpad.pad.PadStatus;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import de.tobias.playpad.view.PseudoClasses;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 
 public class PadStatusListener implements ChangeListener<PadStatus> {
 
-	private IPadViewController controller;
+	private AbstractPadViewController controller;
 
-	public PadStatusListener(IPadViewController controller) {
+	public PadStatusListener(AbstractPadViewController controller) {
 		this.controller = controller;
 	}
 
diff --git a/PlayWall/src/main/java/de/tobias/playpad/trigger/CartTriggerItemFactory.java b/PlayWall/src/main/java/de/tobias/playpad/trigger/CartTriggerItemFactory.java
index 98290adbcd0df99adf16698fe28258999e072a94..e103e69319bbd4457628bb024cc4f812e00d2c66 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/trigger/CartTriggerItemFactory.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/trigger/CartTriggerItemFactory.java
@@ -6,6 +6,7 @@ import de.tobias.playpad.Strings;
 import de.tobias.playpad.tigger.Trigger;
 import de.tobias.playpad.tigger.TriggerItem;
 import de.tobias.playpad.tigger.TriggerItemFactory;
+import de.tobias.playpad.viewcontroller.main.IMainViewController;
 import de.tobias.playpad.viewcontroller.option.pad.trigger.CartTriggerViewController;
 
 public class CartTriggerItemFactory extends TriggerItemFactory {
@@ -20,8 +21,8 @@ public class CartTriggerItemFactory extends TriggerItemFactory {
 	}
 
 	@Override
-	public NVC getSettingsController(TriggerItem item) {
-		return new CartTriggerViewController((CartTriggerItem) item);
+	public NVC getSettingsController(TriggerItem item, IMainViewController mainViewController) {
+		return new CartTriggerViewController((CartTriggerItem) item, mainViewController);
 	}
 
 	@Override
diff --git a/PlayWall/src/main/java/de/tobias/playpad/trigger/TriggerDisplayable.java b/PlayWall/src/main/java/de/tobias/playpad/trigger/TriggerDisplayable.java
index 434a17a2577ee8aee5a27b1a2850134362e350d0..e6a6a6aa5d3748b2cc348230870c16ac1f5e263b 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/trigger/TriggerDisplayable.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/trigger/TriggerDisplayable.java
@@ -10,7 +10,7 @@ import javafx.beans.property.StringProperty;
 
 public class TriggerDisplayable implements Displayable {
 
-	private Trigger trigger;
+	private final Trigger trigger;
 
 	public TriggerDisplayable(Trigger trigger) {
 		this.trigger = trigger;
@@ -21,7 +21,7 @@ public class TriggerDisplayable implements Displayable {
 		return trigger;
 	}
 
-	private StringProperty displayable = new SimpleStringProperty();
+	private final StringProperty displayable = new SimpleStringProperty();
 
 	@Override
 	public StringProperty displayProperty() {
diff --git a/PlayWall/src/main/java/de/tobias/playpad/trigger/VolumeTriggerItemFactory.java b/PlayWall/src/main/java/de/tobias/playpad/trigger/VolumeTriggerItemFactory.java
index 73d2447a29858d8ba7ea630749aa89d8cec357dc..fa908a635f0a02ded7f7e3c4518a21a6c5efef05 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/trigger/VolumeTriggerItemFactory.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/trigger/VolumeTriggerItemFactory.java
@@ -6,6 +6,7 @@ import de.tobias.playpad.Strings;
 import de.tobias.playpad.tigger.Trigger;
 import de.tobias.playpad.tigger.TriggerItem;
 import de.tobias.playpad.tigger.TriggerItemFactory;
+import de.tobias.playpad.viewcontroller.main.IMainViewController;
 import de.tobias.playpad.viewcontroller.option.pad.trigger.VolumeTriggerViewController;
 
 public class VolumeTriggerItemFactory extends TriggerItemFactory {
@@ -20,8 +21,8 @@ public class VolumeTriggerItemFactory extends TriggerItemFactory {
 	}
 
 	@Override
-	public NVC getSettingsController(TriggerItem item) {
-		return new VolumeTriggerViewController((VolumeTriggerItem) item);
+	public NVC getSettingsController(TriggerItem item, IMainViewController mainViewController) {
+		return new VolumeTriggerViewController((VolumeTriggerItem) item, mainViewController);
 	}
 
 	@Override
diff --git a/PlayWall/src/main/java/de/tobias/playpad/util/ListSerializer.java b/PlayWall/src/main/java/de/tobias/playpad/util/ListSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..155d9bdcf0638bd678fb6dae9ab45799963f68e6
--- /dev/null
+++ b/PlayWall/src/main/java/de/tobias/playpad/util/ListSerializer.java
@@ -0,0 +1,35 @@
+package de.tobias.playpad.util;
+
+import de.thecodelabs.storage.settings.UserDefaults;
+import org.dom4j.Element;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ListSerializer implements UserDefaults.Serializer<ArrayList> {
+
+	private static final String LIST_ITEM = "item";
+
+	@Override
+	public ArrayList get(Element element) {
+		ArrayList<Object> list = new ArrayList<>();
+		for (Element child : element.elements(LIST_ITEM)) {
+			final Object o = UserDefaults.loadElement(child);
+			list.add(o);
+		}
+		return list;
+	}
+
+	@Override
+	public void set(Object o, Element element) {
+		if (o instanceof List) {
+			//noinspection unchecked
+			final List<Object> list = (List<Object>) o;
+
+			for (Object item : list) {
+				final Element childElement = element.addElement(LIST_ITEM);
+				UserDefaults.save(childElement, item, null);
+			}
+		}
+	}
+}
diff --git a/PlayWall/src/main/java/de/tobias/playpad/view/FileDragOptionView.java b/PlayWall/src/main/java/de/tobias/playpad/view/FileDragOptionView.java
index 1510b4cfe33d5043e00289a547ccae68be45cac2..38270ca6887aaa067025135443761d2215c55706 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/view/FileDragOptionView.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/view/FileDragOptionView.java
@@ -1,6 +1,7 @@
 package de.tobias.playpad.view;
 
 import de.tobias.playpad.pad.content.PadContentFactory;
+import de.tobias.playpad.pad.drag.ContentDragOption;
 import javafx.animation.FadeTransition;
 import javafx.animation.ParallelTransition;
 import javafx.animation.ScaleTransition;
@@ -14,7 +15,7 @@ import javafx.scene.layout.*;
 import javafx.scene.paint.Color;
 import javafx.scene.text.TextAlignment;
 
-import java.util.Set;
+import java.util.Collection;
 import java.util.function.Consumer;
 
 public class FileDragOptionView implements PadContentFactory.PadContentTypeChooser {
@@ -76,9 +77,9 @@ public class FileDragOptionView implements PadContentFactory.PadContentTypeChoos
 		return parallelTransition;
 	}
 
-	private PadContentFactory selectedConnect;
+	private ContentDragOption selectedConnect;
 
-	public void showOptions(Set<PadContentFactory> options) {
+	public void showOptions(Collection<? extends ContentDragOption> options) {
 		if (!parent.getChildren().contains(optionPane)) {
 			selectedConnect = null;
 
@@ -125,7 +126,7 @@ public class FileDragOptionView implements PadContentFactory.PadContentTypeChoos
 
 	}
 
-	public void showOptions(Set<PadContentFactory> options, Consumer<PadContentFactory> onFinish) {
+	public void showOptions(Collection<PadContentFactory> options, Consumer<PadContentFactory> onFinish) {
 		showOptions(options);
 
 		for (Node node : optionPane.getChildren()) {
@@ -143,7 +144,7 @@ public class FileDragOptionView implements PadContentFactory.PadContentTypeChoos
 		}
 	}
 
-	public PadContentFactory getSelectedConnect() {
+	public ContentDragOption getSelectedConnect() {
 		return selectedConnect;
 	}
 
diff --git a/PlayWall/src/main/java/de/tobias/playpad/view/PadDragOptionView.java b/PlayWall/src/main/java/de/tobias/playpad/view/PadDragOptionView.java
index 205250172cbe517acfb7cb51d1f052de96eae133..7dac34cde41953601b45c78688458d1418ed47ec 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/view/PadDragOptionView.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/view/PadDragOptionView.java
@@ -100,7 +100,7 @@ public class PadDragOptionView {
 			parent.getChildren().add(optionPane);
 			optionPane.getChildren().clear();
 
-			for (PadDragMode connect : options.stream().sorted().toArray(value -> new PadDragMode[value])) {
+			for (PadDragMode connect : options.stream().sorted().toArray(PadDragMode[]::new)) {
 				Label label = new Label();
 				label.getStyleClass().add("dnd-file-option");
 
diff --git a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/main/MainViewController.java b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/main/MainViewController.java
index b2bf4ab78fee9e28884c81cd21fb457db7f1f677..ec8f51a3dfc669a93d119794e71e1f9b2d29ee48 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/main/MainViewController.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/main/MainViewController.java
@@ -363,6 +363,7 @@ public class MainViewController extends NVC implements IMainViewController, Noti
 				}
 			}
 		}
+		Platform.exit();
 		return true;
 	}
 
diff --git a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/GeneralPadTabViewController.java b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/GeneralPadTabViewController.java
index d35275146955d05c9d1625ab4263b1c6735decc9..4e40233ca501ef4edc4c8f2a3c1aca28d042dadb 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/GeneralPadTabViewController.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/GeneralPadTabViewController.java
@@ -9,6 +9,7 @@ import de.tobias.playpad.pad.PadSettings;
 import de.tobias.playpad.pad.PadStatus;
 import de.tobias.playpad.pad.TimeMode;
 import de.tobias.playpad.pad.content.PadContentFactory;
+import de.tobias.playpad.pad.content.Playlistable;
 import de.tobias.playpad.viewcontroller.PadSettingsTabViewController;
 import de.tobias.playpad.viewcontroller.cell.EnumCell;
 import javafx.beans.binding.Bindings;
@@ -16,12 +17,15 @@ import javafx.beans.value.ChangeListener;
 import javafx.event.ActionEvent;
 import javafx.fxml.FXML;
 import javafx.scene.control.*;
+import javafx.scene.layout.VBox;
 import javafx.stage.Stage;
 
 import java.util.Optional;
 
 public class GeneralPadTabViewController extends PadSettingsTabViewController {
 
+	@FXML
+	private VBox mediaRootBox;
 	@FXML
 	private Label pathLabel;
 	@FXML
@@ -55,6 +59,11 @@ public class GeneralPadTabViewController extends PadSettingsTabViewController {
 		}
 		showPathButton.disableProperty().bind(Bindings.isEmpty(pad.getPaths()));
 
+		// Disable media section for playlists
+		if (pad.getContent() instanceof Playlistable) {
+			mediaRootBox.setDisable(true);
+		}
+
 		if (pad.getStatus() == PadStatus.PLAY || pad.getStatus() == PadStatus.PAUSE) {
 			deleteButton.setDisable(true);
 		}
diff --git a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/PadSettingsViewController.java b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/PadSettingsViewController.java
index 9cb33f084def3bdefe0a5610a70e8fc4bf146350..efccf7b0e68031570f6c1e06d0a82ab2de46366f 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/PadSettingsViewController.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/PadSettingsViewController.java
@@ -10,16 +10,17 @@ import de.tobias.playpad.pad.Pad;
 import de.tobias.playpad.pad.PadStatus;
 import de.tobias.playpad.pad.content.PadContentFactory;
 import de.tobias.playpad.pad.content.PadContentRegistry;
+import de.tobias.playpad.pad.content.Playlistable;
 import de.tobias.playpad.registry.NoSuchComponentException;
 import de.tobias.playpad.viewcontroller.IPadSettingsViewController;
 import de.tobias.playpad.viewcontroller.PadSettingsTabViewController;
+import de.tobias.playpad.viewcontroller.main.IMainViewController;
 import javafx.event.ActionEvent;
 import javafx.fxml.FXML;
 import javafx.scene.control.Button;
 import javafx.scene.control.Tab;
 import javafx.scene.control.TabPane;
 import javafx.stage.Stage;
-import javafx.stage.Window;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -35,14 +36,17 @@ public class PadSettingsViewController extends NVC implements IPadSettingsViewCo
 	@FXML
 	private Button finishButton;
 
-	public PadSettingsViewController(Pad pad, Window owner) {
+	public PadSettingsViewController(Pad pad, IMainViewController mainViewController) {
 		load("view/option/pad", "PadSettingsView", Localization.getBundle());
 		this.pad = pad;
 
 		addTab(new GeneralPadTabViewController(pad));
+		if (pad.getContent() instanceof Playlistable) {
+			addTab(new PlaylistTabViewController(pad));
+		}
 		addTab(new DesignPadTabViewController(pad));
 		addTab(new PlayerPadTabViewController(pad));
-		addTab(new TriggerPadTabViewController(pad));
+		addTab(new TriggerPadTabViewController(pad, mainViewController));
 
 		if (pad.getContent() != null) {
 			try {
@@ -61,7 +65,7 @@ public class PadSettingsViewController extends NVC implements IPadSettingsViewCo
 		}
 
 		NVCStage nvcStage = applyViewControllerToStage();
-		nvcStage.initOwner(owner);
+		nvcStage.initOwner(mainViewController.getStage());
 		nvcStage.addCloseHook(this::onFinish);
 		addCloseKeyShortcut(() -> finishButton.fire());
 
@@ -85,7 +89,7 @@ public class PadSettingsViewController extends NVC implements IPadSettingsViewCo
 		stage.getIcons().add(PlayPadPlugin.getInstance().getIcon());
 
 		stage.setMinWidth(650);
-		stage.setMinHeight(550);
+		stage.setMinHeight(600);
 
 		PlayPadPlugin.styleable().applyStyle(stage);
 	}
diff --git a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/PlaylistTabViewController.java b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/PlaylistTabViewController.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a80e87d3169c61af24b9a8fdaf0f233f6cf2979
--- /dev/null
+++ b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/PlaylistTabViewController.java
@@ -0,0 +1,165 @@
+package de.tobias.playpad.viewcontroller.option.pad;
+
+import de.thecodelabs.utils.application.system.NativeApplication;
+import de.thecodelabs.utils.ui.icon.FontAwesomeType;
+import de.thecodelabs.utils.ui.icon.FontIcon;
+import de.thecodelabs.utils.util.Localization;
+import de.tobias.playpad.PlayPadPlugin;
+import de.tobias.playpad.Strings;
+import de.tobias.playpad.layout.desktop.listener.PadNewContentListener;
+import de.tobias.playpad.pad.Pad;
+import de.tobias.playpad.pad.content.PadContentFactory;
+import de.tobias.playpad.pad.content.PadContentRegistry;
+import de.tobias.playpad.pad.content.Playlistable;
+import de.tobias.playpad.pad.mediapath.MediaPath;
+import de.tobias.playpad.viewcontroller.PadSettingsTabViewController;
+import javafx.beans.binding.Bindings;
+import javafx.event.ActionEvent;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+
+public class PlaylistTabViewController extends PadSettingsTabViewController {
+
+	@FXML
+	private ListView<MediaPath> mediaPathListView;
+
+	@FXML
+	private Button addButton;
+	@FXML
+	private Button upButton;
+	@FXML
+	private Button downButton;
+
+	@FXML
+	private Label pathLabel;
+	@FXML
+	private Button deleteButton;
+	@FXML
+	private Button showFileButton;
+
+	private final Pad pad;
+
+	public PlaylistTabViewController(Pad pad) {
+		this.pad = pad;
+		load("view/option/pad", "PlaylistTab", Localization.getBundle());
+
+		mediaPathListView.setItems(pad.getPaths());
+		initButtons();
+	}
+
+	@Override
+	public void init() {
+		addButton.setGraphic(new FontIcon(FontAwesomeType.PLUS));
+		upButton.setGraphic(new FontIcon(FontAwesomeType.ARROW_UP));
+		downButton.setGraphic(new FontIcon(FontAwesomeType.ARROW_DOWN));
+
+		mediaPathListView.setCellFactory(param -> new ListCell<MediaPath>() {
+			@Override
+			protected void updateItem(MediaPath item, boolean empty) {
+				super.updateItem(item, empty);
+				if (!empty) {
+					setText(item.getFileName());
+					final Playlistable playlist = (Playlistable) pad.getContent();
+					if (!playlist.isLoaded(item)) {
+						setGraphic(new FontIcon(FontAwesomeType.WARNING));
+					} else {
+						setGraphic(null);
+					}
+				} else {
+					setText("");
+					setGraphic(null);
+				}
+			}
+		});
+
+		pathLabel.setText(Localization.getString("padSettings.gen.label.media.empty"));
+		mediaPathListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
+			if (newValue != null) {
+				pathLabel.setText(newValue.getPath().toString());
+			} else {
+				pathLabel.setText(Localization.getString("padSettings.gen.label.media.empty"));
+			}
+		});
+	}
+
+	private void initButtons() {
+		upButton.disableProperty()
+				.bind(mediaPathListView.getSelectionModel().selectedItemProperty().isNull()
+						.or(mediaPathListView.getSelectionModel().selectedIndexProperty().isEqualTo(0)));
+		downButton.disableProperty()
+				.bind(mediaPathListView.getSelectionModel().selectedItemProperty().isNull()
+						.or(mediaPathListView.getSelectionModel().selectedIndexProperty().isEqualTo(Bindings.size(mediaPathListView.getItems()).subtract(1))));
+
+		deleteButton.disableProperty().bind(mediaPathListView.getSelectionModel().selectedItemProperty().isNull());
+		showFileButton.disableProperty().bind(mediaPathListView.getSelectionModel().selectedItemProperty().isNull());
+	}
+
+	@Override
+	public String getName() {
+		return Localization.getString(Strings.UI_WINDOW_PAD_SETTINGS_PLAYLIST_TITLE);
+	}
+
+	@Override
+	public void loadSettings(Pad pad) {
+		// Not implemented
+	}
+
+	@Override
+	public void saveSettings(Pad pad) {
+		// Not implemented
+	}
+
+	@FXML
+	public void onAddHandler(ActionEvent event) {
+		final PadContentRegistry padContentRegistry = PlayPadPlugin.getRegistries().getPadContents();
+		final PadContentFactory contentFactory = padContentRegistry.getFactory(pad.getContent().getType());
+
+		final PadNewContentListener padNewContentListener = new PadNewContentListener(pad);
+		final List<File> files = padNewContentListener.showMediaOpenFileChooser(event, contentFactory.getSupportedTypes(), true);
+
+		if (files != null) {
+			for (File file : files) {
+				pad.addPath(file.toPath());
+			}
+		}
+	}
+
+	@FXML
+	public void onUpHandler(ActionEvent event) {
+		final int selectedIndex = mediaPathListView.getSelectionModel().getSelectedIndex();
+		Collections.swap(pad.getPaths(), selectedIndex, selectedIndex - 1);
+		mediaPathListView.getSelectionModel().select(selectedIndex - 1);
+		pad.getContent().reorderMedia();
+	}
+
+	@FXML
+	public void onDownAction(ActionEvent event) {
+		final int selectedIndex = mediaPathListView.getSelectionModel().getSelectedIndex();
+		Collections.swap(pad.getPaths(), selectedIndex, selectedIndex + 1);
+		mediaPathListView.getSelectionModel().select(selectedIndex + 1);
+		pad.getContent().reorderMedia();
+	}
+
+	@FXML
+	public void onShowFileHandler(ActionEvent event) {
+		MediaPath mediaPath = mediaPathListView.getSelectionModel().getSelectedItem();
+		NativeApplication.sharedInstance().showFileInFileViewer(mediaPath.getPath());
+	}
+
+	@FXML
+	public void onDeleteHandler(ActionEvent event) {
+		MediaPath mediaPath = mediaPathListView.getSelectionModel().getSelectedItem();
+		pad.removePath(mediaPath);
+
+		if (pad.getPaths().isEmpty()) {
+			pad.clear();
+		}
+	}
+}
diff --git a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/TriggerPadTabViewController.java b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/TriggerPadTabViewController.java
index 33fd3432634f564d5718ba8fc85d4fc4725a42b7..d9e1d8fc62dee9745734c99a475b77898a0bf5ea 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/TriggerPadTabViewController.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/TriggerPadTabViewController.java
@@ -8,6 +8,7 @@ import de.tobias.playpad.tigger.TriggerPoint;
 import de.tobias.playpad.trigger.TriggerDisplayable;
 import de.tobias.playpad.viewcontroller.PadSettingsTabViewController;
 import de.tobias.playpad.viewcontroller.cell.DisplayableTreeCell;
+import de.tobias.playpad.viewcontroller.main.IMainViewController;
 import de.tobias.playpad.viewcontroller.option.pad.trigger.TriggerPointViewController;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
@@ -26,9 +27,11 @@ public class TriggerPadTabViewController extends PadSettingsTabViewController im
 	@FXML
 	private VBox contentView;
 
-	private Pad pad;
+	private final Pad pad;
+	private final IMainViewController mainViewController;
 
-	TriggerPadTabViewController(Pad pad) {
+	TriggerPadTabViewController(Pad pad, IMainViewController mainViewController) {
+		this.mainViewController = mainViewController;
 		load("view/option/pad", "TriggerTab", Localization.getBundle());
 		this.pad = pad;
 	}
@@ -61,7 +64,7 @@ public class TriggerPadTabViewController extends PadSettingsTabViewController im
 
 		if (newValue != null) {
 			TriggerDisplayable triggerWrapper = newValue.getValue();
-			TriggerPointViewController controller = new TriggerPointViewController(triggerWrapper);
+			TriggerPointViewController controller = new TriggerPointViewController(mainViewController, triggerWrapper);
 			contentView.getChildren().setAll(controller.getParent());
 			VBox.setVgrow(controller.getParent(), Priority.ALWAYS);
 		}
diff --git a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/CartTriggerViewController.java b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/CartTriggerViewController.java
index a5d2f0ea9780c898b90e1ebd98efff2c60d19653..1168ae13aedb828a12ba14ff18c14bad68718a1d 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/CartTriggerViewController.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/CartTriggerViewController.java
@@ -8,6 +8,7 @@ import de.tobias.playpad.pad.PadStatus;
 import de.tobias.playpad.project.Project;
 import de.tobias.playpad.trigger.CartTriggerItem;
 import de.tobias.playpad.view.main.ProjectPreviewView;
+import de.tobias.playpad.viewcontroller.main.IMainViewController;
 import javafx.beans.InvalidationListener;
 import javafx.fxml.FXML;
 import javafx.geometry.Insets;
@@ -25,17 +26,17 @@ public class CartTriggerViewController extends NVC {
 	@FXML
 	private CheckBox allCartsCheckbox;
 
-	private ProjectPreviewView projectPreviewView;
+	private final ProjectPreviewView projectPreviewView;
 
-	private CartTriggerItem item;
+	private final CartTriggerItem item;
 
-	public CartTriggerViewController(CartTriggerItem item) {
+	public CartTriggerViewController(CartTriggerItem item, IMainViewController mainViewController) {
 		load("view/option/pad/trigger", "CartTrigger", Localization.getBundle());
 		this.item = item;
 
 		Project project = PlayPadMain.getProgramInstance().getCurrentProject();
 		final List<Pad> pads = item.getCarts().stream().map(project::getPad).collect(Collectors.toList());
-		projectPreviewView = new ProjectPreviewView(project, pads);
+		projectPreviewView = new ProjectPreviewView(project, pads, mainViewController.getPage());
 		projectPreviewView.setPadding(new Insets(0, 0, 0, 164));
 		projectPreviewView.selectedProperty().addListener((InvalidationListener) observable -> {
 			item.getCarts().clear();
diff --git a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/TriggerPointViewController.java b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/TriggerPointViewController.java
index 77d5166b7191a5da2d5f2565bd1221da47e830b4..85793e58329cc0793f8919085cf1059bd01cb500 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/TriggerPointViewController.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/TriggerPointViewController.java
@@ -10,6 +10,7 @@ import de.tobias.playpad.registry.NoSuchComponentException;
 import de.tobias.playpad.tigger.TriggerItem;
 import de.tobias.playpad.tigger.TriggerItemFactory;
 import de.tobias.playpad.trigger.TriggerDisplayable;
+import de.tobias.playpad.viewcontroller.main.IMainViewController;
 import javafx.fxml.FXML;
 import javafx.scene.control.Button;
 import javafx.scene.control.ContentDisplay;
@@ -26,14 +27,17 @@ public class TriggerPointViewController extends NVC {
 	@FXML
 	private HBox buttonBox;
 
-	private TriggerDisplayable triggerWrapper;
+	private final IMainViewController mainViewController;
+	private final TriggerDisplayable triggerWrapper;
 
-	public TriggerPointViewController(TriggerDisplayable triggerWrapper) {
+	public TriggerPointViewController(IMainViewController mainViewController, TriggerDisplayable triggerWrapper) {
+		this.mainViewController = mainViewController;
 		load("view/option/pad/trigger", "TriggerPoint", Localization.getBundle());
 		this.triggerWrapper = triggerWrapper;
 
-		for (TriggerItem item : triggerWrapper.getTrigger().getItems())
-			showTriggerItem(item);
+		for (TriggerItem item : triggerWrapper.getTrigger().getItems()) {
+			showTriggerItem(item, mainViewController);
+		}
 	}
 
 	@Override
@@ -42,17 +46,17 @@ public class TriggerPointViewController extends NVC {
 		types.stream().sorted().forEach(item ->
 		{
 			try {
-				TriggerItemFactory conntect = PlayPadPlugin.getRegistries().getTriggerItems().getFactory(item);
-				Button button = new Button(conntect.toString(), new FontIcon(FontAwesomeType.PLUS_CIRCLE));
+				TriggerItemFactory factory = PlayPadPlugin.getRegistries().getTriggerItems().getFactory(item);
+				Button button = new Button(factory.toString(), new FontIcon(FontAwesomeType.PLUS_CIRCLE));
 				button.setContentDisplay(ContentDisplay.TOP);
 				button.setPrefWidth(150);
 
 				button.setOnAction(e ->
 				{
-					TriggerItem triggerItem = conntect.newInstance(triggerWrapper.getTrigger());
+					TriggerItem triggerItem = factory.newInstance(triggerWrapper.getTrigger());
 
 					triggerWrapper.addItem(triggerItem);
-					showTriggerItem(triggerItem);
+					showTriggerItem(triggerItem, mainViewController);
 				});
 				buttonBox.getChildren().add(button);
 			} catch (NoSuchComponentException e) {
@@ -61,17 +65,19 @@ public class TriggerPointViewController extends NVC {
 		});
 	}
 
-	private void showTriggerItem(TriggerItem item) {
+	private void showTriggerItem(TriggerItem item, IMainViewController mainViewController) {
 		try {
 			TriggerItemFactory connect = PlayPadPlugin.getRegistries().getTriggerItems().getFactory(item.getType());
 
 			VBox itemBox = new VBox(14);
-			NVC controller = connect.getSettingsController(item);
+			NVC controller = connect.getSettingsController(item, mainViewController);
 			if (controller != null) {
 				itemBox.getChildren().add(controller.getParent());
 
-				NVC timeViewController = new TriggerTimeViewController(item);
-				itemBox.getChildren().add(timeViewController.getParent());
+				if (triggerWrapper.getTrigger().getTriggerPoint().isTimeAppendable()) {
+					final NVC timeViewController = new TriggerTimeViewController(item);
+					itemBox.getChildren().add(timeViewController.getParent());
+				}
 
 				Button deleteButton = new Button("", new FontIcon(FontAwesomeType.TRASH));
 				HBox hbox = new HBox(itemBox, deleteButton);
diff --git a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/VolumeTriggerViewController.java b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/VolumeTriggerViewController.java
index 10a1a70dfb79ad38c6eedcacaa450384a65cdef9..f48a57341e8a354af30dafc4ead00f256d7955f4 100644
--- a/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/VolumeTriggerViewController.java
+++ b/PlayWall/src/main/java/de/tobias/playpad/viewcontroller/option/pad/trigger/VolumeTriggerViewController.java
@@ -8,6 +8,7 @@ import de.tobias.playpad.pad.Pad;
 import de.tobias.playpad.project.Project;
 import de.tobias.playpad.trigger.VolumeTriggerItem;
 import de.tobias.playpad.view.main.ProjectPreviewView;
+import de.tobias.playpad.viewcontroller.main.IMainViewController;
 import javafx.beans.InvalidationListener;
 import javafx.fxml.FXML;
 import javafx.geometry.Insets;
@@ -30,20 +31,20 @@ public class VolumeTriggerViewController extends NVC {
 	private Slider durationSlider;
 	@FXML
 	private Label durationLabel;
-	private ProjectPreviewView projectPreviewView;
+	private final ProjectPreviewView projectPreviewView;
 
-	private VolumeTriggerItem item;
+	private final VolumeTriggerItem item;
 
-	public VolumeTriggerViewController(VolumeTriggerItem item) {
+	public VolumeTriggerViewController(VolumeTriggerItem item, IMainViewController mainViewController) {
 		load("view/option/pad/trigger", "VolumeTrigger", Localization.getBundle());
 		this.item = item;
 
 		volumeSlider.setValue(item.getVolume() * 100.0);
 		durationSlider.setValue(item.getDuration().toSeconds());
 
-		Project project = PlayPadMain.getProgramInstance().getCurrentProject();
+		final Project project = PlayPadMain.getProgramInstance().getCurrentProject();
 		final List<Pad> pads = item.getCarts().stream().map(project::getPad).collect(Collectors.toList());
-		projectPreviewView = new ProjectPreviewView(project, pads);
+		projectPreviewView = new ProjectPreviewView(project, pads, mainViewController.getPage());
 		projectPreviewView.setPadding(new Insets(0, 0, 0, 164));
 		projectPreviewView.selectedProperty().addListener((InvalidationListener) observable -> {
 			item.getCarts().clear();
diff --git a/PlayWall/src/main/resources/lang/_de.properties b/PlayWall/src/main/resources/lang/_de.properties
index 5659469960a8fb5226e22da2c1d3e406d41a382c..33029a528b99644493e53bcd9b83e304ae7fd03d 100755
--- a/PlayWall/src/main/resources/lang/_de.properties
+++ b/PlayWall/src/main/resources/lang/_de.properties
@@ -158,6 +158,7 @@ Info.Mapper.PressKey=Dr\u00FCcken Sie eine Taste auf dem Ger\u00E4t.
 UI.Settings.Alert.NewKeyShortcut.Text=Dr\u00FCcken Sie bitte die gew\u00FCnschte Tastenkombination. \nDieses kann aus Buchstaben, Ziffern und/oder den F-Tasten bestehen.
 # UI - Window - PadSettings
 UI.Window.PadSettings.General.Title=Allgemein
+UI.Window.PadSettings.Playlist.Title=Playlist
 UI.Window.PadSettings.Player.Title=Player
 UI.Window.PadSettings.Layout.Title=Layout
 UI.Window.PadSettings.Trigger.Title=Trigger
@@ -208,14 +209,18 @@ UI.Window.Settings.Updates.CurrentVersion={} (Build {})
 TriggerPoint.toString={} ({})
 Trigger.Cart.Name=Kacheln
 Trigger.Volume.Name=Lautst\u00E4rke
+
 # TriggerPoint - Enum
 TriggerPoint.START=Start
 TriggerPoint.STOP=Stop
-TriggerPoint.EOF=Ende (EoF)
+TriggerPoint.EOF=Ende
+TriggerPoint.EOF_STATE=Ende (EoF)
+
 # Drag and Drop Mode
 DnDMode.Replace=Ersetzen
 DnDMode.Duplicate=Duplizieren
 DnDMode.Move=Tauschen
+DndMode.Playlist=Hinzuf\u00FCgen
 # Main Layout
 MainLayout.Desktop=Desktopmodus
 MainLayout.Touch=Touchmodus
diff --git a/PlayWall/src/main/resources/view/option/pad/GeneralTab.fxml b/PlayWall/src/main/resources/view/option/pad/GeneralTab.fxml
index 897ebd58dca41a69254bfe6b885e6d55cbc1a3fd..918175e2602fd5ef7166f7392ed40efcbc8838ca 100644
--- a/PlayWall/src/main/resources/view/option/pad/GeneralTab.fxml
+++ b/PlayWall/src/main/resources/view/option/pad/GeneralTab.fxml
@@ -3,27 +3,33 @@
 <?import javafx.geometry.Insets?>
 <?import javafx.scene.control.*?>
 <?import javafx.scene.layout.*?>
-<VBox spacing="14.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
+<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
     <children>
-        <HBox alignment="CENTER_LEFT" spacing="14.0">
+        <VBox fx:id="mediaRootBox" spacing="14.0">
             <children>
-                <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%padSettings.gen.label.media"/>
-                <Label fx:id="pathLabel" text="Label" textOverrun="CENTER_ELLIPSIS"/>
-                <VBox HBox.hgrow="ALWAYS"/>
-                <Button fx:id="showPathButton" mnemonicParsing="false" onAction="#showPathButtonHandler" text="%padSettings.button.path.show"/>
+                <HBox alignment="CENTER_LEFT" spacing="14.0">
+                    <children>
+                        <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%padSettings.gen.label.media"/>
+                        <Label fx:id="pathLabel" text="Label" textOverrun="CENTER_ELLIPSIS"/>
+                        <VBox HBox.hgrow="ALWAYS"/>
+                        <Button fx:id="showPathButton" mnemonicParsing="false" onAction="#showPathButtonHandler"
+                                text="%padSettings.button.path.show"/>
+                    </children>
+                </HBox>
+                <HBox spacing="14.0">
+                    <children>
+                        <Button mnemonicParsing="false" onAction="#chooseButtonHandler"
+                                text="%padSettings.button.path.choose"/>
+                        <Button fx:id="deleteButton" mnemonicParsing="false" onAction="#deleteButtonHandler"
+                                text="%padSettings.button.delete"/>
+                    </children>
+                    <padding>
+                        <Insets left="164.0"/>
+                    </padding>
+                </HBox>
+                <Separator prefWidth="200.0"/>
             </children>
-        </HBox>
-        <HBox spacing="14.0">
-            <children>
-                <Button mnemonicParsing="false" onAction="#chooseButtonHandler" text="%padSettings.button.path.choose"/>
-                <Button fx:id="deleteButton" mnemonicParsing="false" onAction="#deleteButtonHandler"
-                        text="%padSettings.button.delete"/>
-            </children>
-            <padding>
-                <Insets left="164.0"/>
-            </padding>
-        </HBox>
-        <Separator prefWidth="200.0"/>
+        </VBox>
         <HBox alignment="CENTER_LEFT" spacing="14.0">
             <children>
                 <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="19.0" prefWidth="150.0"
diff --git a/PlayWall/src/main/resources/view/option/pad/PlaylistTab.fxml b/PlayWall/src/main/resources/view/option/pad/PlaylistTab.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..6f25be3e5792c953ce621d4ae05e0ca0db5b8c8f
--- /dev/null
+++ b/PlayWall/src/main/resources/view/option/pad/PlaylistTab.fxml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" spacing="14.0"
+      xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
+    <children>
+        <VBox spacing="14.0">
+            <children>
+                <ListView fx:id="mediaPathListView" prefWidth="250.0" VBox.vgrow="ALWAYS"/>
+                <HBox spacing="14.0">
+                    <children>
+                        <Button fx:id="addButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false"
+                                onAction="#onAddHandler" HBox.hgrow="ALWAYS"/>
+                        <Button fx:id="upButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false"
+                                onAction="#onUpHandler" HBox.hgrow="ALWAYS"/>
+                        <Button fx:id="downButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false"
+                                onAction="#onDownAction" HBox.hgrow="ALWAYS"/>
+                    </children>
+                </HBox>
+            </children>
+        </VBox>
+        <VBox spacing="14.0">
+            <children>
+                <HBox spacing="14.0">
+                    <children>
+                        <Label fx:id="pathLabel" textOverrun="CENTER_ELLIPSIS"/>
+                    </children>
+                </HBox>
+                <HBox spacing="14.0">
+                    <children>
+                        <Button fx:id="showFileButton" mnemonicParsing="false" onAction="#onShowFileHandler"
+                                text="%padSettings.button.path.show"/>
+                        <Button fx:id="deleteButton" mnemonicParsing="false" onAction="#onDeleteHandler"
+                                text="%padSettings.button.delete"/>
+                    </children>
+                </HBox>
+            </children>
+            <HBox.margin>
+                <Insets/>
+            </HBox.margin>
+            <padding>
+                <Insets bottom="14.0" left="14.0" right="14.0" top="14.0"/>
+            </padding>
+        </VBox>
+    </children>
+    <padding>
+        <Insets bottom="14.0" left="14.0" right="14.0" top="14.0"/>
+    </padding>
+</HBox>
diff --git a/PlayWall/src/main/sass/components/dark-list.scss b/PlayWall/src/main/sass/components/dark-list.scss
new file mode 100644
index 0000000000000000000000000000000000000000..080f181297955b8f85c6922e539e69705d001645
--- /dev/null
+++ b/PlayWall/src/main/sass/components/dark-list.scss
@@ -0,0 +1,23 @@
+@import "variables";
+
+.dark-list {
+	-fx-base: rgb(60, 60, 60);
+
+
+	.list-cell {
+		-fx-skin: "com.sun.javafx.scene.control.skin.ListCellSkin";
+		-fx-background-color: -fx-base;
+		-fx-padding: 10px;
+		-fx-text-fill: #FFFFFF;
+		-fx-opacity: 1;
+
+		&:filled {
+			-fx-border-width: 0px 0px 1px 0px;
+			-fx-border-color: #00000044;
+		}
+
+		&:odd {
+			-fx-background-color: -fx-base;
+		}
+	}
+}
\ No newline at end of file
diff --git a/PlayWall/src/main/sass/components/list.scss b/PlayWall/src/main/sass/components/list.scss
index 1ea1f4bc53dc52ac2bfb04568b503e2d64412451..45bcf857eb7c9f26a7ae5cf1a91c174cf92f75df 100644
--- a/PlayWall/src/main/sass/components/list.scss
+++ b/PlayWall/src/main/sass/components/list.scss
@@ -1,19 +1,22 @@
 @import "variables";
 
-.dark-list {
+.list-view {
 	-fx-base: rgb(60, 60, 60);
 
 
 	.list-cell {
 		-fx-skin: "com.sun.javafx.scene.control.skin.ListCellSkin";
 		-fx-background-color: -fx-base;
-		-fx-padding: 10px;
+		-fx-padding: 4px;
 		-fx-text-fill: #FFFFFF;
 		-fx-opacity: 1;
 
 		&:filled {
 			-fx-border-width: 0px 0px 1px 0px;
-			-fx-border-color: #00000044;
+		}
+
+		&:odd:filled {
+			-fx-background-color: derive(-fx-hover-base, -10%);
 		}
 	}
 
diff --git a/PlayWall/src/main/sass/modern.scss b/PlayWall/src/main/sass/modern.scss
index 7046c6af039f7e778946349465614c6b1a8e9f6b..bb353f6186cc4e1be629a85988ceb1745bdb2908 100644
--- a/PlayWall/src/main/sass/modern.scss
+++ b/PlayWall/src/main/sass/modern.scss
@@ -12,6 +12,7 @@
 @import "components/menu";
 @import "components/toggle-button";
 @import "components/list";
+@import "components/dark-list";
 @import "components/progress-bar";
 @import "components/dialog";
 @import "components/treeview";
diff --git a/PlayWall/src/main/scala/de/tobias/playpad/design/ModernCartDesignHandlerImpl.scala b/PlayWall/src/main/scala/de/tobias/playpad/design/ModernCartDesignHandlerImpl.scala
index aec4ccf9145de83e3b41e86038504f1dbf585ea9..b639f9099419bd956a0b420216f9c01568b2c679 100644
--- a/PlayWall/src/main/scala/de/tobias/playpad/design/ModernCartDesignHandlerImpl.scala
+++ b/PlayWall/src/main/scala/de/tobias/playpad/design/ModernCartDesignHandlerImpl.scala
@@ -4,7 +4,7 @@ import de.thecodelabs.utils.application.ApplicationUtils
 import de.tobias.playpad.design.modern.model.{ModernCartDesign, ModernGlobalDesign}
 import de.tobias.playpad.design.modern.{ModernCartDesignHandler, ModernColor}
 import de.tobias.playpad.pad.content.play.Durationable
-import de.tobias.playpad.pad.viewcontroller.IPadViewController
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController
 import de.tobias.playpad.util.Minifier
 import de.tobias.playpad.view.PseudoClasses
 import javafx.util.Duration
@@ -47,7 +47,7 @@ class ModernCartDesignHandlerImpl extends ModernCartDesignHandler {
 		expressionParser.parseExpression(string, new TemplateParserContext("${", "}")).getValue(context, classOf[String])
 	}
 
-	override def handleWarning(design: ModernCartDesign, controller: IPadViewController, warning: Duration, globalDesign: ModernGlobalDesign): Unit = {
+	override def handleWarning(design: ModernCartDesign, controller: AbstractPadViewController, warning: Duration, globalDesign: ModernGlobalDesign): Unit = {
 		if (globalDesign.isWarnAnimation) {
 			val playColor = design.getPlayColor
 			val backgroundColor = design.getBackgroundColor
@@ -71,5 +71,5 @@ class ModernCartDesignHandlerImpl extends ModernCartDesignHandler {
 		}
 	}
 
-	override def stopWarning(design: ModernCartDesign, controller: IPadViewController): Unit = ModernDesignAnimator.stopAnimation(controller)
+	override def stopWarning(design: ModernCartDesign, controller: AbstractPadViewController): Unit = ModernDesignAnimator.stopAnimation(controller)
 }
diff --git a/PlayWall/src/main/scala/de/tobias/playpad/design/ModernGlobalDesignHandlerImpl.scala b/PlayWall/src/main/scala/de/tobias/playpad/design/ModernGlobalDesignHandlerImpl.scala
index ca1ade7277a8ba8e726e3d3b1844575ea2b47f0b..3eea45b74878a931b801b72ea341ce13375be7d2 100644
--- a/PlayWall/src/main/scala/de/tobias/playpad/design/ModernGlobalDesignHandlerImpl.scala
+++ b/PlayWall/src/main/scala/de/tobias/playpad/design/ModernGlobalDesignHandlerImpl.scala
@@ -1,14 +1,11 @@
 package de.tobias.playpad.design
 
-import java.nio.file.Files
-import java.util.function.Consumer
-
 import de.thecodelabs.utils.application.ApplicationUtils
 import de.thecodelabs.utils.application.container.PathType
 import de.tobias.playpad.design.modern.model.{ModernCartDesign, ModernGlobalDesign}
 import de.tobias.playpad.design.modern.{ModernColor, ModernGlobalDesignHandler}
 import de.tobias.playpad.pad.content.play.Durationable
-import de.tobias.playpad.pad.viewcontroller.IPadViewController
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController
 import de.tobias.playpad.project.Project
 import de.tobias.playpad.util.Minifier
 import de.tobias.playpad.view.{ColorPickerView, PseudoClasses}
@@ -22,6 +19,8 @@ import org.springframework.expression.common.TemplateParserContext
 import org.springframework.expression.spel.standard.SpelExpressionParser
 import org.springframework.expression.spel.support.StandardEvaluationContext
 
+import java.nio.file.Files
+import java.util.function.Consumer
 import scala.jdk.CollectionConverters._
 
 class ModernGlobalDesignHandlerImpl extends ModernGlobalDesignHandler with ColorModeHandler {
@@ -93,7 +92,7 @@ class ModernGlobalDesignHandlerImpl extends ModernGlobalDesignHandler with Color
 		expressionParser.parseExpression(string, new TemplateParserContext("${", "}")).getValue(context, classOf[String])
 	}
 
-	override def handleWarning(design: ModernGlobalDesign, controller: IPadViewController, warning: Duration): Unit = {
+	override def handleWarning(design: ModernGlobalDesign, controller: AbstractPadViewController, warning: Duration): Unit = {
 		if (design.isWarnAnimation) {
 			warnAnimation(design, controller, warning)
 		} else {
@@ -101,7 +100,7 @@ class ModernGlobalDesignHandlerImpl extends ModernGlobalDesignHandler with Color
 		}
 	}
 
-	private def warnAnimation(design: ModernGlobalDesign, controller: IPadViewController, warning: Duration): Unit = {
+	private def warnAnimation(design: ModernGlobalDesign, controller: AbstractPadViewController, warning: Duration): Unit = {
 		val stopColor = if (design.isFlatDesign) design.getBackgroundColor.toFlatFadeableColor else design.getBackgroundColor.toFadeableColor
 		val playColor = if (design.isFlatDesign) design.getPlayColor.toFlatFadeableColor else design.getPlayColor.toFadeableColor
 
@@ -118,7 +117,7 @@ class ModernGlobalDesignHandlerImpl extends ModernGlobalDesignHandler with Color
 		ModernDesignAnimator.animateWarn(controller, playColor, stopColor, duration)
 	}
 
-	override def stopWarning(design: ModernGlobalDesign, controller: IPadViewController): Unit = ModernDesignAnimator.stopAnimation(controller)
+	override def stopWarning(design: ModernGlobalDesign, controller: AbstractPadViewController): Unit = ModernDesignAnimator.stopAnimation(controller)
 
 	override def getColorInterface(onSelection: Consumer[DisplayableColor]) = new ColorPickerView(null, ModernColor.values.asInstanceOf[Array[DisplayableColor]], onSelection)
 
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/design/modern/ModernCartDesignHandler.java b/PlayWallCore/src/main/java/de/tobias/playpad/design/modern/ModernCartDesignHandler.java
index 0f34344711461d7ef8a26a175053fc2be731f27b..200ead1fd6e412137370b6393167bb1092adc90d 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/design/modern/ModernCartDesignHandler.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/design/modern/ModernCartDesignHandler.java
@@ -2,7 +2,7 @@ package de.tobias.playpad.design.modern;
 
 import de.tobias.playpad.design.modern.model.ModernCartDesign;
 import de.tobias.playpad.design.modern.model.ModernGlobalDesign;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import javafx.util.Duration;
 
 public interface ModernCartDesignHandler {
@@ -12,9 +12,9 @@ public interface ModernCartDesignHandler {
 	/*
 	 * Wird in einem neuen Thread aufgerufen
 	 */
-	void handleWarning(ModernCartDesign design, IPadViewController controller, Duration warning, ModernGlobalDesign globalDesign);
+	void handleWarning(ModernCartDesign design, AbstractPadViewController controller, Duration warning, ModernGlobalDesign globalDesign);
 
-	default void stopWarning(ModernCartDesign design, IPadViewController controller) {
+	default void stopWarning(ModernCartDesign design, AbstractPadViewController controller) {
 	}
 
 }
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/design/modern/ModernGlobalDesignHandler.java b/PlayWallCore/src/main/java/de/tobias/playpad/design/modern/ModernGlobalDesignHandler.java
index 1c6930dd44d0737bfce2454d18f96ba131652aff..bca1e4aa9cee672852326f41dffe582e115f10e4 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/design/modern/ModernGlobalDesignHandler.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/design/modern/ModernGlobalDesignHandler.java
@@ -1,7 +1,7 @@
 package de.tobias.playpad.design.modern;
 
 import de.tobias.playpad.design.modern.model.ModernGlobalDesign;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import de.tobias.playpad.project.Project;
 import de.tobias.playpad.viewcontroller.main.IMainViewController;
 import javafx.stage.Stage;
@@ -16,8 +16,8 @@ public interface ModernGlobalDesignHandler {
 	/*
 	 * Wird in einem neuen Thread aufgerufen
 	 */
-	void handleWarning(ModernGlobalDesign design, IPadViewController controller, Duration warning);
+	void handleWarning(ModernGlobalDesign design, AbstractPadViewController controller, Duration warning);
 
-	default void stopWarning(ModernGlobalDesign design, IPadViewController controller) {
+	default void stopWarning(ModernGlobalDesign design, AbstractPadViewController controller) {
 	}
 }
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/Pad.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/Pad.java
index 2a0fd4c28cda491ab99634c36b4f2ac2ac967598..cbefe4d2a0c9c95ce5607e7bcd510b7311212ea9 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/Pad.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/Pad.java
@@ -13,7 +13,7 @@ import de.tobias.playpad.pad.listener.trigger.PadTriggerContentListener;
 import de.tobias.playpad.pad.listener.trigger.PadTriggerDurationListener;
 import de.tobias.playpad.pad.listener.trigger.PadTriggerStatusListener;
 import de.tobias.playpad.pad.mediapath.MediaPath;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import de.tobias.playpad.project.Project;
 import de.tobias.playpad.project.ProjectSettings;
 import de.tobias.playpad.project.page.PadIndex;
@@ -78,7 +78,7 @@ public class Pad {
 	// Utils
 	private transient boolean eof;
 
-	private transient IPadViewController controller;
+	private transient AbstractPadViewController controller;
 	private transient Project project;
 	private transient PadUpdateListener padListener;
 
@@ -323,6 +323,10 @@ public class Pad {
 			createMediaPath(path);
 		} else {
 			setPath(path, 0);
+
+			while (mediaPaths.size() > 1) {
+				mediaPaths.remove(mediaPaths.size() - 1);
+			}
 		}
 	}
 
@@ -350,6 +354,13 @@ public class Pad {
 		addPath(mediaPath);
 	}
 
+	public void addPath(Path path) {
+		if (mediaPaths.isEmpty()) {
+			setName(PathUtils.getFilenameWithoutExtension(path.getFileName()));
+		}
+		createMediaPath(path);
+	}
+
 	public void addPath(MediaPath mediaPath) {
 		mediaPaths.add(mediaPath);
 
@@ -364,6 +375,7 @@ public class Pad {
 	}
 
 	public void removePath(MediaPath path) {
+		getContent().unloadMedia(path);
 		mediaPaths.remove(path);
 	}
 
@@ -374,6 +386,12 @@ public class Pad {
 		}
 	}
 
+	public void clearPaths() {
+		while (!mediaPaths.isEmpty()) {
+			removePath(mediaPaths.get(0));
+		}
+	}
+
 	/**
 	 * Get the status of the pad.
 	 *
@@ -556,11 +574,11 @@ public class Pad {
 		return controller != null;
 	}
 
-	public IPadViewController getController() {
+	public AbstractPadViewController getController() {
 		return controller;
 	}
 
-	public void setController(IPadViewController controller) {
+	public void setController(AbstractPadViewController controller) {
 		this.controller = controller;
 	}
 
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContent.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContent.java
index bf50a0b447c04de9dd77eadb9a9ee6834ca224bc..6c6d943e9f88741e9891794bf5a68fa3d712a7df 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContent.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContent.java
@@ -40,6 +40,10 @@ public abstract class PadContent {
 
 	public abstract boolean isPadLoaded();
 
+	public boolean isPadLoading() {
+		return false;
+	}
+
 	/**
 	 * Load media files.
 	 */
@@ -64,6 +68,9 @@ public abstract class PadContent {
 	 */
 	public abstract void unloadMedia(MediaPath mediaPath);
 
+	public void reorderMedia() {
+	}
+
 	public abstract void updateVolume();
 
 	@Override
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContentFactory.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContentFactory.java
index e300c5a8b8f5f2c5a2c711bbce42629a541d51ef..611654dc50e21a013911b95a49e9024936c9b14b 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContentFactory.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContentFactory.java
@@ -2,20 +2,23 @@ package de.tobias.playpad.pad.content;
 
 import de.thecodelabs.utils.io.PathUtils;
 import de.tobias.playpad.pad.Pad;
+import de.tobias.playpad.pad.drag.ContentDragOption;
 import de.tobias.playpad.pad.view.IPadContentView;
 import de.tobias.playpad.registry.Component;
 import de.tobias.playpad.viewcontroller.PadSettingsTabViewController;
 import de.tobias.playpad.viewcontroller.option.ProfileSettingsTabViewController;
 import javafx.scene.layout.Pane;
 
+import java.io.File;
 import java.nio.file.Path;
-import java.util.Set;
+import java.util.Collection;
+import java.util.List;
 import java.util.function.Consumer;
 
-public abstract class PadContentFactory extends Component implements Comparable<PadContentFactory> {
+public abstract class PadContentFactory extends Component implements ContentDragOption {
 
 	public interface PadContentTypeChooser {
-		void showOptions(Set<PadContentFactory> options, Consumer<PadContentFactory> onSelected);
+		void showOptions(Collection<PadContentFactory> options, Consumer<PadContentFactory> onSelected);
 	}
 
 	public PadContentFactory(String type) {
@@ -36,11 +39,6 @@ public abstract class PadContentFactory extends Component implements Comparable<
 
 	public abstract String[] getSupportedTypes();
 
-	@Override
-	public int compareTo(PadContentFactory o) {
-		return getType().compareTo(o.getType());
-	}
-
 	public static boolean isFileTypeSupported(Path path, PadContentFactory connect) {
 		String extension = PathUtils.getFileExtension(path);
 		for (String ex : connect.getSupportedTypes()) {
@@ -50,4 +48,26 @@ public abstract class PadContentFactory extends Component implements Comparable<
 		}
 		return false;
 	}
+
+	// Generic Drag Option for all content types
+
+	@Override
+	public void handleDrop(Pad currentPad, List<File> files) {
+		if (currentPad.getContent() == null || !currentPad.getContent().getType().equals(getType())) {
+			currentPad.setContentType(getType());
+		}
+
+		if (currentPad.isPadVisible()) {
+			currentPad.getController().getView().showBusyView(true);
+		}
+
+		if (currentPad.getContent() instanceof Playlistable) {
+			currentPad.clearPaths();
+			for (File file : files) {
+				currentPad.addPath(file.toPath());
+			}
+		} else {
+			currentPad.setPath(files.get(0).toPath());
+		}
+	}
 }
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContentRegistry.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContentRegistry.java
index 20e7f45d2ef3f798555acda8d0062c9cad47c5f5..a2614a95f34e7f86294ff57beb87777c818e8bcb 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContentRegistry.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/PadContentRegistry.java
@@ -12,17 +12,30 @@ public class PadContentRegistry extends ComponentRegistry<PadContentFactory> {
 		super(name);
 	}
 
-	public Set<PadContentFactory> getPadContentConnectsForFile(Path path) throws NoSuchComponentException {
-		Set<PadContentFactory> connects = new HashSet<>();
+	public List<PadContentFactory> getPadContentConnectsForFile(Path paths) throws NoSuchComponentException {
+		return getPadContentConnectsForFiles(Collections.singletonList(paths));
+	}
+
+	public List<PadContentFactory> getPadContentConnectsForFiles(List<Path> paths) throws NoSuchComponentException {
+		final Set<PadContentFactory> connects = new HashSet<>();
 		for (String type : getTypes()) {
 			PadContentFactory connect = getFactory(type);
 			for (String extension : connect.getSupportedTypes()) {
-				if (path.getFileName().toString().toLowerCase().matches("." + extension)) {
+				if (isExtensionMatchingAllFiles(extension, paths)) {
 					connects.add(connect);
 				}
 			}
 		}
-		return connects;
+		return new ArrayList<>(connects);
+	}
+
+	private boolean isExtensionMatchingAllFiles(String extension, List<Path> paths) {
+		for (Path path : paths) {
+			if (!path.getFileName().toString().toLowerCase().matches("." + extension)) {
+				return false;
+			}
+		}
+		return true;
 	}
 
 	public String[] getSupportedFileTypes() throws NoSuchComponentException {
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/Playlistable.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/Playlistable.java
new file mode 100644
index 0000000000000000000000000000000000000000..1d15d9ad02184a18dc076b6cce7d739f8eba9552
--- /dev/null
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/content/Playlistable.java
@@ -0,0 +1,16 @@
+package de.tobias.playpad.pad.content;
+
+import de.tobias.playpad.pad.mediapath.MediaPath;
+import javafx.beans.property.IntegerProperty;
+
+public interface Playlistable {
+	int getCurrentPlayingMediaIndex();
+
+	IntegerProperty currentPlayingMediaIndexProperty();
+
+	boolean hasNext();
+
+	void next();
+
+	boolean isLoaded(MediaPath mediaPath);
+}
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/drag/ContentDragOption.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/drag/ContentDragOption.java
new file mode 100644
index 0000000000000000000000000000000000000000..8af2e6d82227376781157fc2f9bd46b9073ce53f
--- /dev/null
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/drag/ContentDragOption.java
@@ -0,0 +1,17 @@
+package de.tobias.playpad.pad.drag;
+
+import de.tobias.playpad.Displayable;
+import de.tobias.playpad.pad.Pad;
+
+import java.io.File;
+import java.util.List;
+
+public interface ContentDragOption extends Displayable, Comparable<ContentDragOption> {
+
+	void handleDrop(Pad currentPad, List<File> files);
+
+	@Override
+	default int compareTo(ContentDragOption o) {
+		return displayProperty().get().compareTo(o.displayProperty().get());
+	}
+}
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/LinearFadeController.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/LinearFadeController.java
new file mode 100644
index 0000000000000000000000000000000000000000..3287ca97157df9df9aac614b43ccd21baa49e94a
--- /dev/null
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/LinearFadeController.java
@@ -0,0 +1,26 @@
+package de.tobias.playpad.pad.fade;
+
+import javafx.animation.Transition;
+
+/**
+ * A fade controller implementation, that handles fade scala linear.
+ *
+ * @author tobias
+ * @since 7.1.0
+ */
+public class LinearFadeController extends AbstractFadeController {
+
+	public LinearFadeController(FadeControllerDelegate fadeDelegate) {
+		super(fadeDelegate);
+	}
+
+	@Override
+	protected void interpolate(Transition transition, double frac, double from, double to) {
+		double diff = Math.abs(to - from);
+		if (from < to) { // Fade In
+			fadeDelegate.onFadeLevelChange(diff * frac);
+		} else { // Fade Out
+			fadeDelegate.onFadeLevelChange(from - (diff * frac));
+		}
+	}
+}
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/listener/PadFadeContentListener.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/listener/PadFadeContentListener.java
index ad414c8d8250053b5a3ec2f279c3b3bfd676e57c..0d7436b3405d2f89be63feebeaf36f55fe213889 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/listener/PadFadeContentListener.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/listener/PadFadeContentListener.java
@@ -7,9 +7,12 @@ import de.tobias.playpad.pad.fade.Fadeable;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 
+/**
+ * Remove end of file fade listener on old pad content and register on new pad content
+ */
 public class PadFadeContentListener implements ChangeListener<PadContent> {
 
-	private Pad pad;
+	private final Pad pad;
 
 	public PadFadeContentListener(Pad pad) {
 		this.pad = pad;
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/listener/PadFadeDurationListener.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/listener/PadFadeDurationListener.java
index b795033f65d4b4004432d8c53d82a8ee0f115939..214f832d81b61a8449170e5443a83a1fa32c57de 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/listener/PadFadeDurationListener.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/listener/PadFadeDurationListener.java
@@ -1,6 +1,7 @@
 package de.tobias.playpad.pad.fade.listener;
 
 import de.tobias.playpad.pad.Pad;
+import de.tobias.playpad.pad.content.Playlistable;
 import de.tobias.playpad.pad.content.play.Durationable;
 import de.tobias.playpad.pad.fade.Fadeable;
 import javafx.beans.value.ChangeListener;
@@ -20,6 +21,16 @@ public class PadFadeDurationListener implements ChangeListener<Duration> {
 		if (pad.getPadSettings().getFade().isFadeOutEof()) {
 			final Duration fadeDuration = pad.getPadSettings().getFade().getFadeOut();
 
+			// Do not fade out if looping is enabled
+			if (pad.getPadSettings().isLoop()) {
+				return;
+			}
+
+			// Do not fade out if the playlist has a next entry
+			if (pad.getContent() instanceof Playlistable && ((Playlistable) pad.getContent()).hasNext()) {
+				return;
+			}
+			
 			if (pad.getContent() instanceof Durationable) {
 				final Durationable durationable = (Durationable) pad.getContent();
 
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/listener/trigger/PadTriggerDurationListener.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/listener/trigger/PadTriggerDurationListener.java
index 5ed71ddb3703d706c5591e14ded194d1481df576..834121676c93bc610e53b4ed255d8c06536991ae 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/listener/trigger/PadTriggerDurationListener.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/listener/trigger/PadTriggerDurationListener.java
@@ -22,22 +22,22 @@ public class PadTriggerDurationListener implements ChangeListener<Duration> {
 	}
 
 	@Override
-	public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
+	public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration currentTime) {
 		PadContent content = pad.getContent();
 		if (content instanceof Durationable) {
 			Duration totalDuration = ((Durationable) content).getDuration();
 			if (totalDuration != null) {
-				Duration leftTime = totalDuration.subtract(newValue);
-
 				IMainViewController mainViewController = PlayPadPlugin.getInstance().getMainViewController();
 				Profile currentProfile = Profile.currentProfile();
 				PadSettings padSettings = pad.getPadSettings();
 
-				// Execute Triggers
-				Trigger startTrigger = padSettings.getTrigger(TriggerPoint.START);
-				startTrigger.handle(pad, newValue, pad.getProject(), mainViewController, currentProfile);
+				// Execute Start Triggers
+				final Trigger startTrigger = padSettings.getTrigger(TriggerPoint.START);
+				startTrigger.handle(pad, currentTime, pad.getProject(), mainViewController, currentProfile);
 
-				Trigger endTrigger = padSettings.getTrigger(TriggerPoint.EOF);
+				// Execute End Trigger
+				final Duration leftTime = totalDuration.subtract(currentTime);
+				final Trigger endTrigger = padSettings.getTrigger(TriggerPoint.EOF);
 				endTrigger.handle(pad, leftTime, pad.getProject(), mainViewController, currentProfile);
 			}
 		}
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/listener/trigger/PadTriggerStatusListener.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/listener/trigger/PadTriggerStatusListener.java
index f7edfbdf7c483255dc437116d980f14832e59d42..94459f05e67e68795cc885c73be904a798fced97 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/listener/trigger/PadTriggerStatusListener.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/listener/trigger/PadTriggerStatusListener.java
@@ -26,12 +26,12 @@ public class PadTriggerStatusListener implements ChangeListener<PadStatus> {
 			PadSettings padSettings = pad.getPadSettings();
 
 			// Execute Trigger
-			if (newValue == PadStatus.PLAY) { // TRIGGER FÜR START
+			if (newValue == PadStatus.PLAY) {
 				executeTrigger(padSettings.getTriggers().get(TriggerPoint.START));
-			} else if (newValue == PadStatus.STOP) { // TRIGGER FÜR STOP
+			} else if (newValue == PadStatus.STOP) {
 				executeTrigger(padSettings.getTriggers().get(TriggerPoint.STOP));
-			} else if (oldValue == PadStatus.PLAY && newValue == PadStatus.READY && pad.isEof()) { // TRIGGER FÜR EOF
-				executeTrigger(padSettings.getTriggers().get(TriggerPoint.EOF));
+			} else if (oldValue == PadStatus.PLAY && newValue == PadStatus.READY && pad.isEof()) {
+				executeTrigger(padSettings.getTriggers().get(TriggerPoint.EOF_STATE));
 			}
 		} else {
 			pad.setIgnoreTrigger(false);
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/mediapath/MediaPath.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/mediapath/MediaPath.java
index 2287d7e5ac335b679cbf05975645bbd2e0737b97..64b1eb68e81f22260754f63fd089efdc97fcc12b 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/mediapath/MediaPath.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/mediapath/MediaPath.java
@@ -19,8 +19,8 @@ import java.util.UUID;
  */
 public class MediaPath {
 
-	private UUID id;
-	private StringProperty fileName;
+	private final UUID id;
+	private final StringProperty fileName;
 	private Pad pad;
 
 	public MediaPath(UUID id, Path path, Pad pad) {
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/preview/PadTextPreview.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/preview/PadTextPreview.java
new file mode 100644
index 0000000000000000000000000000000000000000..714792cb845c075ea42c739964af5f1b44ef8fa7
--- /dev/null
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/preview/PadTextPreview.java
@@ -0,0 +1,40 @@
+package de.tobias.playpad.pad.preview;
+
+import de.tobias.playpad.pad.Pad;
+import de.tobias.playpad.pad.view.IPadContentView;
+import javafx.geometry.Pos;
+import javafx.scene.Parent;
+import javafx.scene.control.Label;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.TextAlignment;
+
+public class PadTextPreview implements IPadContentView {
+
+	private final Label nameLabel;
+
+	public PadTextPreview(Pad pad, Pane parentNode) {
+		this.nameLabel = new Label();
+		this.nameLabel.textProperty().bind(pad.nameProperty());
+
+		this.nameLabel.setWrapText(true);
+		this.nameLabel.setAlignment(Pos.CENTER);
+		this.nameLabel.setTextAlignment(TextAlignment.CENTER);
+
+		this.nameLabel.prefWidthProperty().bind(parentNode.widthProperty());
+		this.nameLabel.setMaxHeight(Double.MAX_VALUE);
+
+		VBox.setVgrow(nameLabel, Priority.ALWAYS);
+	}
+
+	@Override
+	public Parent getNode() {
+		return nameLabel;
+	}
+
+	@Override
+	public void deInit() {
+		nameLabel.textProperty().unbind();
+	}
+}
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/view/IPadContentView.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/view/IPadContentView.java
index c91aa9c7651afdc804ed1e961bf8cf80a1744338..62c5c08f19d5f9dfae5feddd12b5020c1a0e4be6 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/view/IPadContentView.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/view/IPadContentView.java
@@ -1,6 +1,6 @@
 package de.tobias.playpad.pad.view;
 
-import javafx.scene.Node;
+import javafx.scene.Parent;
 
 // TODO Rename to ContentView
 
@@ -17,7 +17,7 @@ public interface IPadContentView {
 	 *
 	 * @return GUI Element
 	 */
-	Node getNode();
+	Parent getNode();
 
 	/**
 	 * Deinitialisiert die View. Hier können mögliche Bindings und Listener entfernt werden.
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/view/IPadView.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/view/IPadView.java
index 51c6ae1b2d7450bf0cd0c191d822bc7f43be7beb..fd2be672d536176e22eb2a1097acca69a666be8e 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/view/IPadView.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/view/IPadView.java
@@ -1,9 +1,10 @@
 package de.tobias.playpad.pad.view;
 
 import de.tobias.playpad.pad.Pad;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import de.tobias.playpad.project.page.PadIndex;
 import javafx.css.PseudoClass;
+import javafx.scene.control.Label;
 import javafx.scene.layout.Pane;
 
 /**
@@ -33,7 +34,7 @@ public interface IPadView {
 	 *
 	 * @return ViewController des Pad
 	 */
-	IPadViewController getViewController();
+	AbstractPadViewController getViewController();
 
 	/**
 	 * Gibt das oberste GUI Element des Pads zurück, welche im MainView verwendet wird.
@@ -106,6 +107,8 @@ public interface IPadView {
 	 */
 	void setPlaybarVisible(boolean visible);
 
+	Label getPlaylistLabel();
+
 	/**
 	 * Fügt die Standart Elemente der PadView hinzu. Die GUI Element sind Abhängig vom Pad, und welchen Content es hat.
 	 *
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/viewcontroller/AbstractPadViewController.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/viewcontroller/AbstractPadViewController.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1cbb5372b4768424ceae0a0f1cee17adf0a6527
--- /dev/null
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/viewcontroller/AbstractPadViewController.java
@@ -0,0 +1,71 @@
+package de.tobias.playpad.pad.viewcontroller;
+
+import de.tobias.playpad.pad.Pad;
+import de.tobias.playpad.pad.content.Playlistable;
+import de.tobias.playpad.pad.listener.IPadPositionListener;
+import de.tobias.playpad.pad.view.IPadView;
+import javafx.beans.binding.Bindings;
+import javafx.beans.value.ChangeListener;
+import javafx.util.Duration;
+
+/**
+ * Schnittstellen um mit einem PadViewController zu kommunizieren.
+ *
+ * @author tobias
+ * @since 5.1.0
+ */
+public abstract class AbstractPadViewController {
+
+	/**
+	 * Gibt das Pad zurück, welches er verwaltet. (Das Datenmodel)
+	 *
+	 * @return Pad
+	 */
+	public abstract Pad getPad();
+
+	/**
+	 * Gibt die View des Controllers zurück.
+	 *
+	 * @return View
+	 */
+	public abstract IPadView getView();
+
+	/**
+	 * Setzt ein Pad für ein View. Hier werden die Datein mittels ViewController der View bekannt gemacht.
+	 *
+	 * @param pad Neues Pad
+	 */
+	public abstract void setupPad(Pad pad);
+
+	/**
+	 * Entfertn des Verbundene Pad von der View.
+	 */
+	public abstract void removePad();
+
+	public abstract void updateTimeLabel();
+
+	public abstract void updateButtonDisable();
+
+	public abstract IPadPositionListener getPadPositionListener();
+
+	public abstract ChangeListener<Duration> getPadDurationListener();
+
+	public void updatePlaylistLabelBinding(Pad pad) {
+		if (pad.getContent() instanceof Playlistable) {
+			final Playlistable content = (Playlistable) pad.getContent();
+			getView().getPlaylistLabel().textProperty().bind(Bindings.createStringBinding(() -> {
+				final int currentPlayingMediaIndex = content.getCurrentPlayingMediaIndex();
+				final int totalCount = pad.getPaths().size();
+
+				if (currentPlayingMediaIndex < 0) {
+					return "- / " + totalCount;
+				} else {
+					return (currentPlayingMediaIndex + 1) + " / " + totalCount;
+				}
+			}, content.currentPlayingMediaIndexProperty(), pad.getPaths()));
+		} else {
+			getView().getPlaylistLabel().textProperty().unbind();
+			getView().getPlaylistLabel().setText("");
+		}
+	}
+}
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/viewcontroller/IPadViewController.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/viewcontroller/IPadViewController.java
deleted file mode 100644
index 6c010518809856910286625e81179040dfcb5c13..0000000000000000000000000000000000000000
--- a/PlayWallCore/src/main/java/de/tobias/playpad/pad/viewcontroller/IPadViewController.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package de.tobias.playpad.pad.viewcontroller;
-
-import de.tobias.playpad.pad.Pad;
-import de.tobias.playpad.pad.listener.IPadPositionListener;
-import de.tobias.playpad.pad.view.IPadView;
-import javafx.beans.value.ChangeListener;
-import javafx.util.Duration;
-
-/**
- * Schnittstellen um mit einem PadViewController zu kommunizieren.
- *
- * @author tobias
- * @since 5.1.0
- */
-public interface IPadViewController {
-
-	/**
-	 * Gibt das Pad zurück, welches er verwaltet. (Das Datenmodel)
-	 *
-	 * @return Pad
-	 */
-	Pad getPad();
-
-	/**
-	 * Gibt die View des Controllers zurück.
-	 *
-	 * @return View
-	 */
-	IPadView getView();
-
-	/**
-	 * Setzt ein Pad für ein View. Hier werden die Datein mittels ViewController der View bekannt gemacht.
-	 *
-	 * @param pad Neues Pad
-	 */
-	void setupPad(Pad pad);
-
-	/**
-	 * Entfertn des Verbundene Pad von der View.
-	 */
-	void removePad();
-
-	void updateTimeLabel();
-
-	void updateButtonDisable();
-
-	IPadPositionListener getPadPositionListener();
-
-	ChangeListener<Duration> getPadDurationListener();
-}
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/profile/Profile.java b/PlayWallCore/src/main/java/de/tobias/playpad/profile/Profile.java
index 4900d036b2a09c0e936c85cbc6e5b52bebea9964..7e50c4dc4866467c22a06cc7372e830b28cd36e7 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/profile/Profile.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/profile/Profile.java
@@ -17,9 +17,7 @@ import org.dom4j.DocumentException;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
 
 public class Profile {
 
@@ -30,11 +28,13 @@ public class Profile {
 	private static Profile currentProfile;
 
 	// Settings
-	private ProfileReference ref;
+	private final ProfileReference ref;
 
 	private ProfileSettings profileSettings;
 	private MappingCollection mappings;
 
+	private Map<String, Object> customSettings;
+
 	/**
 	 * Use {@link ProfileReferenceManager#addProfile(ProfileReference)} instead
 	 *
@@ -44,6 +44,7 @@ public class Profile {
 		this.ref = ref;
 		this.profileSettings = new ProfileSettings();
 		this.mappings = new MappingCollection();
+		this.customSettings = new HashMap<>();
 	}
 
 	public static Mapping createMappingWithDefaultActions() {
@@ -84,6 +85,14 @@ public class Profile {
 		return profileSettings;
 	}
 
+	public Object getCustomSettings(String name) {
+		return customSettings.get(name);
+	}
+
+	public void addCustomSettings(String name, Object settings) {
+		customSettings.put(name, settings);
+	}
+
 	public static Profile load(ProfileReference ref) throws DocumentException, IOException, ProfileNotFoundException {
 		if (ref == null) {
 			throw new IllegalArgumentException("Profile is null");
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/tigger/Trigger.java b/PlayWallCore/src/main/java/de/tobias/playpad/tigger/Trigger.java
index fcfb8301d15073275508a66799bdc0f2a20244f1..ba284a16cccbe20166ac9c86c41fbb9a822dc5e5 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/tigger/Trigger.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/tigger/Trigger.java
@@ -104,20 +104,22 @@ public class Trigger {
 		return triggerPoint.name() + " (" + items.size() + ")";
 	}
 
-	public void handle(Pad pad, Duration duration, Project project, IMainViewController mainViewController, Profile currentProfile) {
+	public void handle(Pad pad, Duration currentDuration, Project project, IMainViewController mainViewController, Profile currentProfile) {
 		for (TriggerItem item : items) {
 			if (triggerPoint == TriggerPoint.START) {
-				handleStartPoint(pad, duration, project, mainViewController, currentProfile, item);
+				handleStartPoint(pad, currentDuration, project, mainViewController, currentProfile, item);
 			} else if (triggerPoint == TriggerPoint.STOP) {
-				handleEndPoint(pad, duration, project, mainViewController, currentProfile, item);
+				handleEndPoint(pad, currentDuration, project, mainViewController, currentProfile, item);
 			} else if (triggerPoint == TriggerPoint.EOF) {
-				handleEndPoint(pad, duration, project, mainViewController, currentProfile, item);
+				handleEndPoint(pad, currentDuration, project, mainViewController, currentProfile, item);
+			} else if (triggerPoint == TriggerPoint.EOF_STATE) {
+				item.performAction(pad, project, mainViewController, currentProfile);
 			}
 		}
 	}
 
 	private void handleEndPoint(Pad pad, Duration duration, Project project, IMainViewController mainViewController, Profile currentProfile, TriggerItem item) {
-		// Wenn Trigger noch nicht gespiel wurde (null) und Zeit größer ist als gesetzte Zeit (oder 0)
+		// Wenn Trigger noch nicht gespielt wurde (null) und Zeit größer ist als gesetzte Zeit (oder 0)
 		if (item.getPerformedAt() == null && (item.getDurationFromPoint().greaterThan(duration) || duration.equals(Duration.ZERO))) {
 			item.performAction(pad, project, mainViewController, currentProfile);
 			item.setPerformedAt(duration);
@@ -128,7 +130,7 @@ public class Trigger {
 
 	private void handleStartPoint(Pad pad, Duration duration, Project project, IMainViewController mainViewController, Profile currentProfile, TriggerItem item) {
 		if (pad.getStatus() == PadStatus.PLAY) {
-			// Mitten drin, wenn die Zeit die gespiel wurde größer ist als die gesetzte und noch der Trigger noch nicht ausgeführt
+			// Mitten drin, wenn die Zeit die gespielt wurde größer ist als die gesetzte und noch der Trigger noch nicht ausgeführt
 			// wurde (null)
 			if ((item.getPerformedAt() == null && item.getDurationFromPoint().lessThan(duration))
 					// Wenn der Trigger am Anfang ist
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/tigger/TriggerItemFactory.java b/PlayWallCore/src/main/java/de/tobias/playpad/tigger/TriggerItemFactory.java
index 9590d921a24a86a84453ff83acbcce147cb69c91..118dc56017638413688062a0bd742f59ffc05dec 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/tigger/TriggerItemFactory.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/tigger/TriggerItemFactory.java
@@ -2,6 +2,7 @@ package de.tobias.playpad.tigger;
 
 import de.thecodelabs.utils.ui.NVC;
 import de.tobias.playpad.registry.Component;
+import de.tobias.playpad.viewcontroller.main.IMainViewController;
 
 public abstract class TriggerItemFactory extends Component {
 
@@ -11,6 +12,6 @@ public abstract class TriggerItemFactory extends Component {
 
 	public abstract TriggerItem newInstance(Trigger trigger);
 
-	public abstract NVC getSettingsController(TriggerItem item);
+	public abstract NVC getSettingsController(TriggerItem item, IMainViewController mainViewController);
 
 }
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/tigger/TriggerPoint.java b/PlayWallCore/src/main/java/de/tobias/playpad/tigger/TriggerPoint.java
index c25fb939321d8b292cf5db86ea7bd7cf3ee7c10d..4f1390d9e6ebda63f92fe7647d00ae0fe759df2c 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/tigger/TriggerPoint.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/tigger/TriggerPoint.java
@@ -2,8 +2,21 @@ package de.tobias.playpad.tigger;
 
 public enum TriggerPoint {
 
-	START,
-	STOP,
-	EOF
+	START(true),
+	STOP(false),
+	EOF(true),
+	EOF_STATE(false);
 
+	/**
+	 * Defines if a trigger can be run after, before a certain event.
+	 */
+	private final boolean timeAppendable;
+
+	TriggerPoint(boolean timeAppendable) {
+		this.timeAppendable = timeAppendable;
+	}
+
+	public boolean isTimeAppendable() {
+		return timeAppendable;
+	}
 }
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/view/main/MainLayoutFactory.java b/PlayWallCore/src/main/java/de/tobias/playpad/view/main/MainLayoutFactory.java
index f7cf7399636ec98235da323c9e75f1c23a0631f1..88039dcb374505f9f913fc81b4d72d5c20fdfd63 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/view/main/MainLayoutFactory.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/view/main/MainLayoutFactory.java
@@ -1,7 +1,7 @@
 package de.tobias.playpad.view.main;
 
 import de.tobias.playpad.pad.view.IPadView;
-import de.tobias.playpad.pad.viewcontroller.IPadViewController;
+import de.tobias.playpad.pad.viewcontroller.AbstractPadViewController;
 import de.tobias.playpad.registry.Component;
 import de.tobias.playpad.viewcontroller.main.IMainViewController;
 import de.tobias.playpad.viewcontroller.main.MenuToolbarViewController;
@@ -31,7 +31,7 @@ public abstract class MainLayoutFactory extends Component {
 	 *
 	 * @return Pad
 	 * @see IPadView notwendige Methoden für ein Pad
-	 * @see IPadViewController ViewController zum Pad
+	 * @see AbstractPadViewController ViewController zum Pad
 	 */
 	public abstract IPadView createPadView();
 
diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/view/main/ProjectPreviewView.java b/PlayWallCore/src/main/java/de/tobias/playpad/view/main/ProjectPreviewView.java
index 10bba54fef944f0b3dd71fe6a651bf867b4a54f7..2e16c3cb79abe3471b9e6c0c185852f9efb87816 100644
--- a/PlayWallCore/src/main/java/de/tobias/playpad/view/main/ProjectPreviewView.java
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/view/main/ProjectPreviewView.java
@@ -6,6 +6,9 @@ import de.tobias.playpad.project.Project;
 import de.tobias.playpad.project.page.Page;
 import javafx.collections.FXCollections;
 import javafx.collections.ObservableList;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
 import javafx.scene.control.Pagination;
 import javafx.scene.control.ToggleButton;
 import javafx.scene.control.Tooltip;
@@ -15,31 +18,36 @@ import java.util.List;
 
 public class ProjectPreviewView extends Pagination {
 
-	private Project project;
+	private final Project project;
+	private final ObservableList<Pad> selected;
 
-	private ObservableList<Pad> selected;
-
-	public ProjectPreviewView(Project project, List<Pad> preSelect) {
+	public ProjectPreviewView(Project project, List<Pad> preSelect, int initialPage) {
 		super(project.getPages().size());
 		this.project = project;
 		this.selected = FXCollections.observableArrayList(preSelect);
 
-		setPageFactory(index -> {
-			GridPane gridPane = new GridPane();
-			gridPane.setHgap(7);
-			gridPane.setVgap(7);
+		setCurrentPageIndex(initialPage);
+		setPageFactory(this::getPageNode);
+	}
+
+	private Node getPageNode(int index) {
+		GridPane gridPane = new GridPane();
+		gridPane.setHgap(7);
+		gridPane.setVgap(7);
+		gridPane.setAlignment(Pos.CENTER);
 
-			Page page = project.getPage(index);
-			for (int x = 0; x < project.getSettings().getColumns(); x++) {
-				for (int y = 0; y < project.getSettings().getRows(); y++) {
-					final Pad pad = page.getPad(x, y);
-					ToggleButton toggleButton = getToggleButton(preSelect, pad);
+		gridPane.setPadding(new Insets(0, 0, 7, 0));
 
-					gridPane.add(toggleButton, x, y);
-				}
+		final Page page = project.getPage(index);
+		for (int x = 0; x < project.getSettings().getColumns(); x++) {
+			for (int y = 0; y < project.getSettings().getRows(); y++) {
+				final Pad pad = page.getPad(x, y);
+				ToggleButton toggleButton = getToggleButton(selected, pad);
+
+				gridPane.add(toggleButton, x, y);
 			}
-			return gridPane;
-		});
+		}
+		return gridPane;
 	}
 
 	private ToggleButton getToggleButton(List<Pad> preSelect, Pad pad) {
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/pom.xml b/PlayWallPlugins/PlayWallPluginContentPlayer/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f888ba1cdefe38357b672f8f58debe259874dbf7
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/pom.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>PlayWallPlugins</artifactId>
+        <groupId>de.tobias.playpad</groupId>
+        <version>7.0.2</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>PlayWallPluginContentPlayer</artifactId>
+
+    <properties>
+        <project.outputDirectory>../../build/${project.version}</project.outputDirectory>
+        <project.artifactName>${project.artifactId}-v${project.version}</project.artifactName>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>de.tobias.playpad</groupId>
+            <artifactId>PlayWallCore</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>de.thecodelabs</groupId>
+                <artifactId>versionizer-maven-plugin</artifactId>
+                <version>${versionizer-maven-plugin.version}</version>
+                <configuration>
+                    <resourceFile>plugin.yml</resourceFile>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>resource-fill</id>
+                        <goals>
+                            <goal>resource-fill</goal>
+                        </goals>
+                        <phase>compile</phase>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!--Scala Plugin-->
+            <plugin>
+                <groupId>net.alchim31.maven</groupId>
+                <artifactId>scala-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>scala-compile-first</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                            <goal>compile</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>scala-test-compile</id>
+                        <phase>process-test-resources</phase>
+                        <goals>
+                            <goal>testCompile</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>3.1.1</version>
+                <configuration>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                    <outputDirectory>${project.outputDirectory}</outputDirectory>
+                    <finalName>${project.artifactName}</finalName>
+                    <appendAssemblyId>false</appendAssemblyId>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>assemble-all</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <distributionManagement>
+        <repository>
+            <id>release</id>
+            <name>TheCodeLabs-releases</name>
+            <url>https://maven.thecodelabs.de/artifactory/TheCodeLabs-release</url>
+        </repository>
+        <snapshotRepository>
+            <id>snapshots</id>
+            <name>TheCodeLabs-snapshots</name>
+            <url>https://maven.thecodelabs.de/artifactory/TheCodeLabs-snapshots</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <repositories>
+        <repository>
+            <id>release</id>
+            <url>https://maven.thecodelabs.de/artifactory/TheCodeLabs-release</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+        <repository>
+            <id>snapshots</id>
+            <url>https://maven.thecodelabs.de/artifactory/TheCodeLabs-snapshots</url>
+            <releases>
+                <enabled>false</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+
+</project>
\ No newline at end of file
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/PadContent.xml b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/PadContent.xml
new file mode 100644
index 0000000000000000000000000000000000000000..32da3b2a4dcc9e49a66cbac1a9bb23b5528c2a53
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/PadContent.xml
@@ -0,0 +1,6 @@
+<Actions>
+    <Component id="content_player" name="plugin.content.Player.name" icon="MONITOR_MULTIPLE"
+               class="de.thecodelabs.utils.ui.icon.MaterialDesignIcon"
+               size="30">de.tobias.playpad.plugin.content.pad.ContentPlayerPadContentFactory
+    </Component>
+</Actions>
\ No newline at end of file
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/lang/base.properties b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/lang/base.properties
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/lang/base_de.properties b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/lang/base_de.properties
new file mode 100644
index 0000000000000000000000000000000000000000..f349884fe1a09c06e16bd93793838ac6430afbb8
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/lang/base_de.properties
@@ -0,0 +1,17 @@
+plugin.content.Player.name=Content Player
+
+plugin.content.player.settings=Content Player
+plugin.content.player.settings.name=Name:
+plugin.content.player.settings.x=X:
+plugin.content.player.settings.y=Y:
+plugin.content.player.settings.width=Breite:
+plugin.content.player.settings.height=H\u00F6he:
+plugin.content.player.settings.add=Hinzuf\u00FCgen
+plugin.content.player.settings.remove=L\u00F6schen
+plugin.content.player.settings.default_name=Zone
+
+plugin.content.pad.settings.lastFrame.label=Letztes Frame halten
+plugin.content.pad.settings.lastFrame.checkbox=Aktiv
+plugin.content.pad.settings.zone=Zonen
+plugin.content.pad.settings.zone.addAll=Alle anw\u00E4hlen
+plugin.content.pad.settings.zone.removeAll=Alle abw\u00E4hlen
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/plugin.yml b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/plugin.yml
new file mode 100644
index 0000000000000000000000000000000000000000..70a18e12c0441bf59f78ee543ce885c15034c894
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/plugin.yml
@@ -0,0 +1,6 @@
+main: "de.tobias.playpad.plugin.content.ContentPluginMain"
+name: "ContentPlugin"
+artifactId: "${pom.artifactId}"
+groupId: "${pom.groupId}"
+version: "${pom.version}"
+build: 1
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/view/ContentPadSettings.fxml b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/view/ContentPadSettings.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..bfd7033978d027d36f881bb9957b7c158056cb89
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/view/ContentPadSettings.fxml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+<?import org.controlsfx.control.CheckListView?>
+<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
+    <children>
+        <VBox layoutX="237.0" layoutY="-18.0" spacing="14.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
+            <children>
+                <HBox alignment="CENTER_LEFT" spacing="14.0">
+                    <children>
+                        <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%plugin.content.pad.settings.lastFrame.label" />
+                        <CheckBox fx:id="lastFrameCheckbox" mnemonicParsing="false" text="%plugin.content.pad.settings.lastFrame.checkbox" />
+                    </children>
+                </HBox>
+            <HBox spacing="14.0">
+               <children>
+                  <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%plugin.content.pad.settings.zone" />
+                  <CheckListView fx:id="zoneListView" prefHeight="150.0" />
+                  <VBox spacing="14.0">
+                     <children>
+                        <Button fx:id="addAllZonesButton" onAction="#onAddAllZonesHandler" mnemonicParsing="false" text="%plugin.content.pad.settings.zone.addAll" />
+                        <Button fx:id="removeAllZonesButton" onAction="#onRemoveAllZonesHandler" mnemonicParsing="false" text="%plugin.content.pad.settings.zone.removeAll" />
+                     </children>
+                  </VBox>
+               </children>
+            </HBox>
+            </children>
+            <padding>
+                <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" />
+            </padding>
+        </VBox>
+    </children>
+</AnchorPane>
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/view/PlayerView.fxml b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/view/PlayerView.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..3428c4ea773b6b4a8e3838f54f9373d77107c718
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/view/PlayerView.fxml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+<?import javafx.scene.layout.Pane?>
+<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" />
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/view/ZoneSettings.fxml b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/view/ZoneSettings.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..64036902597eb22c98b1b9881eee56e6aad82a12
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/resources/view/ZoneSettings.fxml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import de.thecodelabs.utils.ui.scene.input.NumberTextField?>
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
+    <children>
+      <VBox layoutY="345.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0">
+         <children>
+              <ListView fx:id="listView" prefWidth="250.0" VBox.vgrow="ALWAYS" />
+              <HBox prefHeight="30.0" prefWidth="200.0" spacing="14.0">
+                  <children>
+                      <Button fx:id="addButton" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#onAddHandle" text="%plugin.content.player.settings.add" HBox.hgrow="ALWAYS" />
+                      <Button fx:id="removeButton" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#onRemoveHandle" text="%plugin.content.player.settings.remove" HBox.hgrow="ALWAYS" />
+                  </children>
+               <padding>
+                  <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" />
+               </padding>
+              </HBox>
+         </children>
+      </VBox>
+        <VBox layoutX="200.0" prefHeight="400.0" prefWidth="401.0" spacing="14.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="250.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
+            <children>
+                <HBox alignment="CENTER_LEFT" spacing="14.0">
+                    <children>
+                        <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%plugin.content.player.settings.name" />
+                        <TextField fx:id="nameTextField" />
+                    </children>
+                </HBox>
+                <HBox alignment="CENTER_LEFT" spacing="14.0">
+                    <children>
+                        <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%plugin.content.player.settings.x" />
+                        <NumberTextField fx:id="xTextField" />
+                    </children>
+                </HBox>
+                <HBox alignment="CENTER_LEFT" spacing="14.0">
+                    <children>
+                        <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%plugin.content.player.settings.y" />
+                        <NumberTextField fx:id="yTextField" />
+                    </children>
+                </HBox>
+                <HBox alignment="CENTER_LEFT" spacing="14.0">
+                    <children>
+                        <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%plugin.content.player.settings.width" />
+                        <NumberTextField fx:id="widthTextField" />
+                    </children>
+                </HBox>
+                <HBox alignment="CENTER_LEFT" spacing="14.0">
+                    <children>
+                        <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%plugin.content.player.settings.height" />
+                        <NumberTextField fx:id="heightTextField" />
+                    </children>
+                </HBox>
+            </children>
+            <padding>
+                <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" />
+            </padding>
+        </VBox>
+    </children>
+</AnchorPane>
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/ContentPluginMain.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/ContentPluginMain.scala
new file mode 100644
index 0000000000000000000000000000000000000000..2756703ed75e039767b9c5ba3e09324f46653b98
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/ContentPluginMain.scala
@@ -0,0 +1,60 @@
+package de.tobias.playpad.plugin.content
+
+import de.thecodelabs.plugins.PluginDescriptor
+import de.thecodelabs.storage.settings.{Storage, StorageTypes}
+import de.thecodelabs.utils.util.Localization
+import de.tobias.playpad.PlayPadPlugin
+import de.tobias.playpad.plugin.content.player.ContentPlayerViewController
+import de.tobias.playpad.plugin.content.settings.{ZoneConfiguration, ZoneSettingsViewController}
+import de.tobias.playpad.plugin.{Module, PlayPadPluginStub, SettingsListener}
+import de.tobias.playpad.profile.{Profile, ProfileListener}
+import javafx.application.Platform
+
+class ContentPluginMain extends PlayPadPluginStub with SettingsListener with ProfileListener {
+
+	private var module: Module = _
+
+	override def startup(descriptor: PluginDescriptor): Unit = {
+		module = new Module(descriptor.getName, descriptor.getArtifactId)
+
+		val localization = Localization.loadBundle("lang/base", getClass.getClassLoader)
+		Localization.addResourceBundle(localization)
+
+		PlayPadPlugin.getRegistries.getPadContents.loadComponentsFromFile("PadContent.xml", getClass.getClassLoader, module, localization)
+		PlayPadPlugin.getInstance().addAdditionalProfileSettingsTab(() => new ZoneSettingsViewController)
+
+		PlayPadPlugin.getInstance().addSettingsListener(this)
+		Profile.registerListener(this)
+	}
+
+	override def shutdown(): Unit = {
+		ContentPluginMain.playerViewController.getStageContainer.ifPresent(container => container.forceClose())
+	}
+
+	override def getModule: Module = module
+
+	override def onLoad(profile: Profile): Unit = {
+		val path = profile.getRef.getCustomFilePath("Zones.json")
+		val zoneConfiguration = Storage.load(path, StorageTypes.JSON, classOf[ZoneConfiguration])
+		profile.addCustomSettings(ContentPluginMain.zoneConfigurationKey, zoneConfiguration)
+	}
+
+	override def onSave(profile: Profile): Unit = {
+		val path = profile.getRef.getCustomFilePath("Zones.json")
+		val zoneConfigurationObject = profile.getCustomSettings(ContentPluginMain.zoneConfigurationKey)
+		if (zoneConfigurationObject != null) {
+			Storage.save(path, StorageTypes.JSON, zoneConfigurationObject)
+		}
+	}
+
+	override def reloadSettings(oldProfile: Profile, currentProfile: Profile): Unit = {
+		val zoneConfiguration = currentProfile.getCustomSettings(ContentPluginMain.zoneConfigurationKey).asInstanceOf[ZoneConfiguration]
+		Platform.runLater(() => ContentPluginMain.playerViewController.configurePlayers(zoneConfiguration))
+	}
+}
+
+object ContentPluginMain {
+	lazy val playerViewController: ContentPlayerViewController = new ContentPlayerViewController
+
+	val zoneConfigurationKey = "ZoneConfiguration"
+}
\ No newline at end of file
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerMediaContainer.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerMediaContainer.scala
new file mode 100644
index 0000000000000000000000000000000000000000..3c298dcbfb2fcf167ef3d682cf03bb71c3d6c9da
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerMediaContainer.scala
@@ -0,0 +1,57 @@
+package de.tobias.playpad.plugin.content.pad
+
+import de.tobias.playpad.pad.PadStatus
+import de.tobias.playpad.pad.mediapath.MediaPath
+import de.tobias.playpad.plugin.content.ContentPluginMain
+import de.tobias.playpad.plugin.content.util._
+import javafx.scene.media.MediaPlayer
+import javafx.util.Duration
+
+class ContentPlayerMediaContainer(val content: ContentPlayerPadContent, val path: MediaPath, val mediaPlayer: MediaPlayer) {
+	def play(): Unit = {
+		content._durationProperty.bind(mediaPlayer.totalDurationProperty())
+		content._positionProperty.bind(mediaPlayer.currentTimeProperty())
+		ContentPluginMain.playerViewController.showMediaPlayer(content.getPad.getPadIndex, mediaPlayer, content.getSelectedZones)
+
+		mediaPlayer.seek(Duration.ZERO)
+		mediaPlayer.play()
+
+		content.getPad.setEof(false)
+		content.currentPlayingMediaIndexProperty().set(content.getMediaPlayers.indexOf(this))
+	}
+
+	def resume(): Unit = {
+		mediaPlayer.play()
+	}
+
+	def pause(): Unit = {
+		mediaPlayer.pause()
+	}
+
+	def next(): Unit = {
+		stop()
+
+		val players = content.getMediaPlayers
+		val index = players.indexOf(this)
+		content.currentPlayingMediaIndexProperty().set(index)
+
+		if (index + 1 < players.length) {
+			players(index + 1).play()
+		} else if (content.getPad.getPadSettings.isLoop) {
+			players.head.play()
+		} else {
+			content.getPad.setStatus(PadStatus.STOP)
+		}
+	}
+
+	def stop(): Unit = {
+		mediaPlayer.stop()
+		ContentPluginMain.playerViewController.disconnectMediaPlayer(mediaPlayer, content.getSelectedZones)
+
+		content._durationProperty.bind(content.totalDurationBinding())
+		content._positionProperty.unbind()
+		content._positionProperty.set(Duration.ZERO)
+	}
+
+	override def toString: String = f"MediaPlayerContainer: $path"
+}
\ No newline at end of file
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContent.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContent.scala
new file mode 100644
index 0000000000000000000000000000000000000000..c1db519a17b8119362c64e7385ba26d91f2b9a40
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContent.scala
@@ -0,0 +1,322 @@
+package de.tobias.playpad.plugin.content.pad
+
+import de.thecodelabs.logger.Logger
+import de.tobias.playpad.pad.content.play.{Durationable, Pauseable}
+import de.tobias.playpad.pad.content.{PadContent, Playlistable}
+import de.tobias.playpad.pad.fade.{Fadeable, LinearFadeController}
+import de.tobias.playpad.pad.mediapath.MediaPath
+import de.tobias.playpad.pad.{Pad, PadStatus}
+import de.tobias.playpad.plugin.content.ContentPluginMain
+import de.tobias.playpad.plugin.content.settings.{Zone, ZoneConfiguration}
+import de.tobias.playpad.plugin.content.util._
+import de.tobias.playpad.profile.Profile
+import de.tobias.playpad.volume.VolumeManager
+import javafx.application.Platform
+import javafx.beans.binding.{Bindings, ObjectBinding}
+import javafx.beans.property._
+import javafx.collections.{FXCollections, ObservableList}
+import javafx.scene.media.{Media, MediaPlayer}
+import javafx.util.Duration
+
+import java.nio.file.Files
+import java.util
+import java.util.Optional
+import java.util.stream.Collectors
+import scala.jdk.CollectionConverters._
+
+class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadContent(pad) with Pauseable with Durationable with Playlistable with Fadeable {
+
+	private val mediaPlayers: ObservableList[ContentPlayerMediaContainer] = FXCollections.observableArrayList()
+	private val currentRunningIndexProperty: IntegerProperty = new SimpleIntegerProperty(-1)
+
+	private[pad] val _durationProperty = new SimpleObjectProperty[Duration]
+	private[pad] val _positionProperty = new SimpleObjectProperty[Duration]
+
+	private var showingLastFrame: Boolean = false
+	private var isPause: Boolean = false
+
+	private val fadeController = new LinearFadeController(value => {
+		if (getCurrentPlayingMediaIndex >= 0) {
+			ContentPluginMain.playerViewController
+				.setFadeValue(mediaPlayers(getCurrentPlayingMediaIndex).mediaPlayer, getSelectedZones, value)
+		}
+	})
+
+	override def getType: String = `type`
+
+	override def getCurrentPlayingMediaIndex: Int = currentRunningIndexProperty.get()
+
+	override def currentPlayingMediaIndexProperty(): IntegerProperty = currentRunningIndexProperty
+
+	def getMediaPlayers: ObservableList[ContentPlayerMediaContainer] = mediaPlayers
+
+	override def hasNext: Boolean = getCurrentPlayingMediaIndex + 1 < mediaPlayers.length
+
+	/*
+	Control Methods
+	 */
+
+	override def play(): Unit = {
+		if (isPause) {
+			mediaPlayers(getCurrentPlayingMediaIndex).resume()
+		} else {
+			ContentPluginMain.playerViewController.addActivePadToList(getPad.getPadIndex, getSelectedZones)
+
+			getPad.setEof(false)
+			mediaPlayers.head.play()
+		}
+		showingLastFrame = false
+		isPause = false
+	}
+
+	override def pause(): Unit = {
+		isPause = true
+		mediaPlayers(getCurrentPlayingMediaIndex).pause()
+	}
+
+	override def next(): Unit = {
+		mediaPlayers(getCurrentPlayingMediaIndex).next()
+	}
+
+	override def stop(): Boolean = {
+		isPause = false
+		mediaPlayers(getCurrentPlayingMediaIndex).stop()
+		currentRunningIndexProperty.set(-1)
+
+		ContentPluginMain.playerViewController.removeActivePadFromList(getPad.getPadIndex, getSelectedZones)
+		true
+	}
+
+	def onEof(): Unit = {
+		if (isFadeActive) {
+			ContentPluginMain.playerViewController.removeActivePadFromList(getPad.getPadIndex, getSelectedZones)
+			return
+		}
+
+		if (shouldShowLastFrame() && !showingLastFrame // Only is settings is enabled and not already in last frame state
+			&& !pad.getPadSettings.isLoop // Only go to last frame state, is looping is disabled
+		) {
+			getPad.setStatus(PadStatus.PAUSE)
+			showingLastFrame = true
+			return
+		}
+
+		showingLastFrame = false
+
+		if (getPad.isEof) {
+			mediaPlayers(getCurrentPlayingMediaIndex).next()
+			return
+		}
+	}
+
+	/*
+	Durationable
+	 */
+
+	override def getDuration: Duration = _durationProperty.get()
+
+	override def getPosition: Duration = _positionProperty.get()
+
+	override def durationProperty(): ReadOnlyObjectProperty[Duration] = _durationProperty
+
+	override def positionProperty(): ReadOnlyObjectProperty[Duration] = _positionProperty
+
+	def totalDurationBinding(): ObjectBinding[Duration] = {
+		Bindings.createObjectBinding(() => mediaPlayers.stream()
+			.map(player => player.mediaPlayer.getTotalDuration)
+			.filter(duration => duration != null)
+			.reduce(Duration.ZERO, (o1: Duration, o2: Duration) => o1.add(o2)),
+			mediaPlayers.stream().map(player => {
+				if (player.mediaPlayer != null) {
+					player.mediaPlayer.totalDurationProperty()
+				} else {
+					null
+				}
+			})
+				.filter(o => o != null)
+				.toArray(size => new Array[ReadOnlyObjectProperty[Duration]](size)): _*)
+	}
+
+	/*
+	Fadeable
+	 */
+
+	override def fadeIn(): Unit = {
+		val fadeIn = getPad.getPadSettings.getFade.getFadeIn
+		if (fadeIn.toMillis > 0) {
+			fadeController.fadeIn(fadeIn)
+		}
+	}
+
+	override def fadeOut(onFinish: Runnable): Unit = {
+		val fadeOut = getPad.getPadSettings.getFade.getFadeOut
+		if (fadeOut.toMillis > 0) {
+			fadeController.fadeOut(fadeOut, () => {
+				if (onFinish != null) onFinish.run()
+
+				if (getPad.getStatus == PadStatus.PLAY) {
+					getPad.setStatus(PadStatus.STOP)
+				}
+			})
+		}
+		else {
+			onFinish.run()
+		}
+	}
+
+	override def isFadeActive: Boolean = fadeController.isFading
+
+	override def fade(from: Double, to: Double, duration: Duration, onFinish: Runnable): Unit = {
+		fadeController.fade(from, to, duration, onFinish)
+	}
+
+	/*
+	Loading
+	 */
+
+	override def isPadLoaded: Boolean = {
+		mediaPlayers.isNotEmpty && !mediaPlayers.stream().anyMatch(player => player.mediaPlayer.getStatus == MediaPlayer.Status.UNKNOWN)
+	}
+
+	override def isLoaded(mediaPath: MediaPath): Boolean = {
+		val loadedOptional: Optional[Boolean] = mediaPlayers.stream()
+			.filter(item => item.path == mediaPath)
+			.findFirst()
+			.map(container => container.mediaPlayer.getStatus != MediaPlayer.Status.UNKNOWN)
+		loadedOptional.orElse(false)
+	}
+
+
+	override def isPadLoading: Boolean = mediaPlayers.stream().anyMatch(player => player.mediaPlayer.getStatus == MediaPlayer.Status.UNKNOWN)
+
+	/**
+	 * Load media files.
+	 */
+	override def loadMedia(): Unit = {
+		mediaPlayers.clear()
+		getPad.getPaths.forEach(loadMedia(_))
+	}
+
+	/**
+	 * Load media file.
+	 *
+	 * @param mediaPath specify media path
+	 */
+	override def loadMedia(mediaPath: MediaPath): Unit = {
+		val path = mediaPath.getPath
+		if (Files.notExists(path)) {
+			Platform.runLater(() => getPad.setStatus(PadStatus.NOT_FOUND))
+			return
+		}
+
+		val media = new Media(path.toUri.toString)
+		val mediaPlayer = new MediaPlayer(media)
+
+		mediaPlayer.setOnReady(() => {
+			getPad.setStatus(PadStatus.READY)
+
+			_durationProperty.bind(totalDurationBinding())
+			_positionProperty.set(Duration.ZERO)
+
+			Platform.runLater(() => {
+				if (getPad.isPadVisible) {
+					getPad.getController.getView.showBusyView(false)
+				}
+			})
+		})
+
+		mediaPlayer.errorProperty().addListener((_, _, newValue) => Platform.runLater(() => {
+			Logger.error(newValue)
+			pad.setStatus(PadStatus.ERROR)
+		}))
+		mediaPlayer.setOnError(() => Platform.runLater(() => {
+			if (getPad.isPadVisible) {
+				getPad.getController.getView.showBusyView(false)
+			}
+			Logger.error(mediaPlayer.getError)
+			pad.setStatus(PadStatus.ERROR)
+		}))
+
+		mediaPlayer.setOnEndOfMedia(() => {
+			getPad.setEof(true)
+			onEof()
+		})
+
+		mediaPlayers.add(new ContentPlayerMediaContainer(this, mediaPath, mediaPlayer))
+	}
+
+	/**
+	 * Unload media files.
+	 */
+	override def unloadMedia(): Unit = {
+		if ((getPad.getStatus eq PadStatus.PLAY) || (getPad.getStatus eq PadStatus.PAUSE)) getPad.setStatus(PadStatus.STOP)
+
+		mediaPlayers.clear()
+
+		Platform.runLater(() => {
+			if (getPad != null) {
+				getPad.setStatus(PadStatus.EMPTY)
+			}
+		})
+	}
+
+	/**
+	 * Unload media file.
+	 *
+	 * @param mediaPath specify media path
+	 */
+	override def unloadMedia(mediaPath: MediaPath): Unit = {
+		val index = mediaPlayers.indexWhere(item => item.path.getId == mediaPath.getId)
+
+		if (index >= 0) {
+			val playerContainer = mediaPlayers(index)
+			playerContainer.stop()
+			mediaPlayers.remove(index)
+		}
+	}
+
+	override def reorderMedia(): Unit = {
+		val paths = pad.getPaths
+		mediaPlayers.sort((o1, o2) => Integer.compare(paths.indexOf(o1.path), paths.indexOf(o2.path)))
+	}
+
+	/*
+	 Volume
+	 */
+
+	override def updateVolume(): Unit = {
+		val volume = VolumeManager.getInstance.computeVolume(getPad)
+		mediaPlayers.forEach(player => player.mediaPlayer.setVolume(volume))
+	}
+
+	/**
+	 * Create a copy of the PadContent instance
+	 *
+	 * @param pad target pad
+	 * @return copied content
+	 */
+	override def copy(pad: Pad): PadContent = {
+		val clone = new ContentPlayerPadContent(pad, getType)
+		clone.loadMedia()
+		clone
+	}
+
+	/*
+	Custom Settings
+	 */
+
+	def shouldShowLastFrame(): Boolean = {
+		pad.getPadSettings.getCustomSettings.getOrDefault(ContentPlayerPadContentFactory.lastFrame, false).asInstanceOf[Boolean]
+	}
+
+	def getSelectedZones: Seq[Zone] = {
+		val zoneConfiguration = Profile.currentProfile().getCustomSettings(ContentPluginMain.zoneConfigurationKey).asInstanceOf[ZoneConfiguration]
+
+		val customSettings = pad.getPadSettings.getCustomSettings
+		val selectedZoneNames = customSettings.getOrDefault(
+			ContentPlayerPadContentFactory.zones,
+			zoneConfiguration.zones.stream().map(zone => zone.getName).collect(Collectors.toList())
+		).asInstanceOf[util.List[String]]
+		zoneConfiguration.zones.asScala.filter(zone => selectedZoneNames.contains(zone.getName)).toSeq
+	}
+}
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContentFactory.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContentFactory.scala
new file mode 100644
index 0000000000000000000000000000000000000000..d08958d5da016d424a9204a12317b8fbade30f93
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContentFactory.scala
@@ -0,0 +1,25 @@
+package de.tobias.playpad.plugin.content.pad
+
+import de.tobias.playpad.pad.Pad
+import de.tobias.playpad.pad.content.{PadContent, PadContentFactory}
+import de.tobias.playpad.pad.view.IPadContentView
+import de.tobias.playpad.viewcontroller.PadSettingsTabViewController
+import javafx.scene.layout.Pane
+
+class ContentPlayerPadContentFactory(val `type`: String) extends PadContentFactory(`type`) {
+
+	override def newInstance(pad: Pad): PadContent = new ContentPlayerPadContent(pad, getType)
+
+	override def getPadContentPreview(pad: Pad, parentNode: Pane): IPadContentView = new ContentPlayerPadPreview(pad, parentNode)
+
+	override def getSettingsViewController(pad: Pad): PadSettingsTabViewController = new ContentPlayerPadContentSettingsViewController(pad)
+
+	override def getSupportedTypes: Array[String] = ContentPlayerPadContentFactory.FILE_EXTENSION
+}
+
+object ContentPlayerPadContentFactory {
+	private val FILE_EXTENSION = Array("*.mp4", "*.mov")
+
+	val lastFrame = "ContentLastFrame"
+	val zones = "zones"
+}
\ No newline at end of file
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContentSettingsViewController.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContentSettingsViewController.scala
new file mode 100644
index 0000000000000000000000000000000000000000..14d5e0ee477047de962dfd5959c2ee67d0a9c1c8
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContentSettingsViewController.scala
@@ -0,0 +1,73 @@
+package de.tobias.playpad.plugin.content.pad
+
+import java.util
+
+import de.thecodelabs.utils.util.Localization
+import de.tobias.playpad.pad.Pad
+import de.tobias.playpad.plugin.content.ContentPluginMain
+import de.tobias.playpad.plugin.content.settings.{Zone, ZoneConfiguration}
+import de.tobias.playpad.profile.Profile
+import de.tobias.playpad.viewcontroller.PadSettingsTabViewController
+import javafx.beans.binding.Bindings
+import javafx.fxml.FXML
+import javafx.scene.control.{Button, CheckBox}
+import org.controlsfx.control.CheckListView
+
+import scala.jdk.CollectionConverters._
+
+class ContentPlayerPadContentSettingsViewController(val pad: Pad) extends PadSettingsTabViewController {
+
+	@FXML
+	var lastFrameCheckbox: CheckBox = _
+	@FXML
+	var zoneListView: CheckListView[Zone] = _
+
+	@FXML
+	var addAllZonesButton: Button = _
+	@FXML
+	var removeAllZonesButton: Button = _
+
+	load("view", "ContentPadSettings", Localization.getBundle)
+
+	override def init(): Unit = {
+		val zoneConfiguration = Profile.currentProfile().getCustomSettings(ContentPluginMain.zoneConfigurationKey).asInstanceOf[ZoneConfiguration]
+		zoneListView.getItems.addAll(zoneConfiguration.zones)
+
+		addAllZonesButton.disableProperty().bind(Bindings.equal(Bindings.size(zoneListView.getCheckModel.getCheckedIndices), zoneListView.getItems.size()))
+		removeAllZonesButton.disableProperty().bind(Bindings.isEmpty(zoneListView.getCheckModel.getCheckedIndices))
+	}
+
+	override def getName: String = Localization.getString("plugin.content.player.settings")
+
+	override def loadSettings(pad: Pad): Unit = {
+		val customSettings = pad.getPadSettings.getCustomSettings
+		val lastFrameOption = customSettings.get(ContentPlayerPadContentFactory.lastFrame)
+		if (lastFrameOption != null) {
+			lastFrameCheckbox.setSelected(lastFrameOption.toString.toBoolean)
+		}
+
+		pad.getContent match {
+			case content: ContentPlayerPadContent =>
+				content.getSelectedZones.foreach(item => zoneListView.getCheckModel.check(item))
+			case _ =>
+		}
+	}
+
+	override def saveSettings(pad: Pad): Unit = {
+		val customSettings = pad.getPadSettings.getCustomSettings
+		customSettings.put(ContentPlayerPadContentFactory.lastFrame, lastFrameCheckbox.isSelected)
+
+		val selectedZoneNames = zoneListView.getCheckModel.getCheckedItems.asScala.map(zone => zone.getName)
+		customSettings.put(ContentPlayerPadContentFactory.zones, new util.ArrayList(selectedZoneNames.asJavaCollection))
+	}
+
+	@FXML
+	def onAddAllZonesHandler(): Unit = {
+		zoneListView.getCheckModel.checkAll()
+	}
+
+	@FXML
+	def onRemoveAllZonesHandler(): Unit = {
+		zoneListView.getCheckModel.clearChecks()
+	}
+}
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadPreview.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadPreview.scala
new file mode 100644
index 0000000000000000000000000000000000000000..6ff298194c1ec57c2f6e7262b8c1c96db6498476
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadPreview.scala
@@ -0,0 +1,68 @@
+package de.tobias.playpad.plugin.content.pad
+
+import de.thecodelabs.utils.io.PathUtils
+import de.tobias.playpad.pad.Pad
+import de.tobias.playpad.pad.view.IPadContentView
+import javafx.beans.binding.Bindings
+import javafx.collections.ListChangeListener
+import javafx.geometry.{Insets, Pos}
+import javafx.scene.Parent
+import javafx.scene.control.Label
+import javafx.scene.layout.{Pane, Priority, VBox}
+import javafx.scene.text.TextAlignment
+
+class ContentPlayerPadPreview(pad: Pad, parent: Pane) extends VBox with IPadContentView {
+
+	val nameLabel: Label = new Label()
+	val subTitleLabel: Label = new Label()
+
+	setupLabel(nameLabel)
+	setupLabel(subTitleLabel)
+
+	getChildren.addAll(nameLabel, subTitleLabel)
+	setSpacing(3)
+	setPadding(new Insets(7))
+
+	getStyleClass.addListener(new ListChangeListener[String] {
+		override def onChanged(c: ListChangeListener.Change[_ <: String]): Unit = {
+			while (c.next()) {
+				if (c.wasRemoved()) {
+					nameLabel.getStyleClass.removeAll(c.getRemoved)
+					subTitleLabel.getStyleClass.removeAll(c.getRemoved)
+				}
+
+				if (c.wasAdded()) {
+					nameLabel.getStyleClass.addAll(c.getAddedSubList)
+					subTitleLabel.getStyleClass.addAll(c.getAddedSubList)
+				}
+			}
+		}
+	})
+
+	nameLabel.textProperty.bind(pad.nameProperty)
+	pad.getContent match {
+		case content: ContentPlayerPadContent =>
+			subTitleLabel.textProperty().bind(Bindings.createStringBinding(() => {
+				if (content.getCurrentPlayingMediaIndex < 0) "" else PathUtils.getFilenameWithoutExtension(pad.getPaths.get(content.getCurrentPlayingMediaIndex).getPath.getFileName)
+			}, content.currentPlayingMediaIndexProperty()))
+		case _ =>
+	}
+
+	private def setupLabel(label: Label): Unit = {
+		label.setWrapText(true)
+		label.setAlignment(Pos.CENTER)
+		label.setTextAlignment(TextAlignment.CENTER)
+
+		label.prefWidthProperty.bind(parent.widthProperty)
+		label.setMaxHeight(Double.MaxValue)
+
+		VBox.setVgrow(label, Priority.ALWAYS)
+	}
+
+	override def getNode: Parent = this
+
+	override def deInit(): Unit = {
+		nameLabel.textProperty().unbind()
+		subTitleLabel.textProperty().unbind()
+	}
+}
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/player/ContentPlayerViewController.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/player/ContentPlayerViewController.scala
new file mode 100644
index 0000000000000000000000000000000000000000..c659e296cd880469fcae5e27ca2f5b193fad0258
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/player/ContentPlayerViewController.scala
@@ -0,0 +1,118 @@
+package de.tobias.playpad.plugin.content.player
+
+import de.thecodelabs.logger.Logger
+import de.thecodelabs.utils.ui.size.IgnoreStageSizing
+import de.thecodelabs.utils.ui.{NVC, NVCStage}
+import de.tobias.playpad.PlayPadPlugin
+import de.tobias.playpad.plugin.content.settings.{Zone, ZoneConfiguration}
+import de.tobias.playpad.project.page.PadIndex
+import javafx.geometry.Insets
+import javafx.scene.layout._
+import javafx.scene.media.MediaPlayer
+import javafx.scene.paint.Color
+import javafx.stage.{Stage, StageStyle}
+
+import scala.collection.mutable.ListBuffer
+
+@IgnoreStageSizing
+class ContentPlayerViewController extends NVC {
+
+	private val mediaStacks: ListBuffer[MediaPlayerStack] = ListBuffer.empty
+
+	load("view", "PlayerView")
+	private val stageContainer: NVCStage = applyViewControllerToStage
+	stageContainer.addCloseHook(() => false)
+
+	Logger.debug("Create Player View Controller")
+
+	override def init(): Unit = {
+		val parent = getParent.asInstanceOf[Pane]
+		parent.setBackground(new Background(new BackgroundFill(Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY)))
+	}
+
+	override def initStage(stage: Stage): Unit = {
+		super.initStage(stage)
+		stage.initStyle(StageStyle.UNDECORATED)
+		stage.setAlwaysOnTop(true)
+
+		stage.getScene.setFill(Color.BLACK)
+		stage.getIcons.add(PlayPadPlugin.getInstance().getIcon)
+	}
+
+	def showMediaPlayer(padIndex: PadIndex, mediaPlayer: MediaPlayer, zones: Seq[Zone]): Unit = {
+		val iterator = this.mediaStacks.iterator
+		while (iterator.hasNext) {
+			val mediaPlayerStack = iterator.next()
+			if (zones.contains(mediaPlayerStack.zone)) {
+				mediaPlayerStack.showMediaPlayer(padIndex, mediaPlayer)
+			}
+		}
+	}
+
+	def disconnectMediaPlayer(mediaPlayer: MediaPlayer, zones: Seq[Zone]): Unit = {
+		val iterator = this.mediaStacks.iterator
+		while (iterator.hasNext) {
+			val mediaPlayerStack = iterator.next()
+			if (zones.contains(mediaPlayerStack.zone)) {
+				mediaPlayerStack.disconnectMediaPlayer(mediaPlayer)
+			}
+		}
+	}
+
+	def configurePlayers(configuration: ZoneConfiguration): Unit = {
+		if (configuration.zones.isEmpty) {
+			closeStage()
+			return
+		}
+
+		val parent = getParent.asInstanceOf[Pane]
+		parent.getChildren.clear()
+
+		mediaStacks.clear()
+		configuration.zones.forEach(player => {
+			val mediaPlayerStack = new MediaPlayerStack(player)
+			mediaStacks.addOne(mediaPlayerStack)
+			parent.getChildren.add(mediaPlayerStack)
+		})
+
+		showStage()
+
+		getStageContainer.ifPresent(container => {
+			val stage = container.getStage
+
+			import scala.jdk.CollectionConverters._
+			val zones = configuration.zones.asScala
+			val maxWidth = zones.map(player => player.x + player.width).max
+			val maxHeight = zones.map(player => player.y + player.height).max
+
+			stage.setX(0)
+			stage.setY(0)
+			stage.setWidth(maxWidth)
+			stage.setHeight(maxHeight)
+		})
+	}
+
+	def addActivePadToList(padIndex: PadIndex, zones: Seq[Zone]): Unit = getMediaStacks(zones)
+		.foreach(mediaStack => mediaStack.addActivePad(padIndex))
+
+	def removeActivePadFromList(padIndex: PadIndex, zones: Seq[Zone]): Unit = getMediaStacks(zones)
+		.foreach(mediaStack => mediaStack.removeActivePad(padIndex))
+
+	def highlight(zone: Zone, on: Boolean): Unit = {
+		if (getMediaStack(zone).isEmpty) {
+			return
+		}
+		getMediaStack(zone).head.highlight(on)
+	}
+
+	def setFadeValue(mediaPlayer: MediaPlayer, zones: Seq[Zone], value: Double): Unit = getMediaStacks(zones)
+		.foreach(mediaStack => mediaStack.setFadeValue(mediaPlayer, value))
+
+	private def getMediaStack(zone: Zone): ListBuffer[MediaPlayerStack] = {
+		getMediaStacks(List(zone))
+	}
+
+	private def getMediaStacks(zones: Seq[Zone]): ListBuffer[MediaPlayerStack] = {
+		mediaStacks.filter(mediaPlayer => zones.contains(mediaPlayer.zone))
+	}
+}
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/player/MediaPlayerStack.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/player/MediaPlayerStack.scala
new file mode 100644
index 0000000000000000000000000000000000000000..15d3872130e3fe4b1d32c3ff3d67f11329a70c6d
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/player/MediaPlayerStack.scala
@@ -0,0 +1,78 @@
+package de.tobias.playpad.plugin.content.player
+
+import java.util.stream.Collectors
+
+import de.thecodelabs.logger.Logger
+import de.tobias.playpad.plugin.content.settings.Zone
+import de.tobias.playpad.project.page.PadIndex
+import javafx.geometry.Insets
+import javafx.scene.layout.{Background, BackgroundFill, CornerRadii, StackPane}
+import javafx.scene.media.{MediaPlayer, MediaView}
+import javafx.scene.paint.Color
+
+import scala.collection.mutable
+import scala.collection.mutable.ListBuffer
+
+class MediaPlayerStack(val zone: Zone) extends StackPane {
+
+	private var activePlayers: ListBuffer[PadIndex] = ListBuffer.empty
+	val mediaViews: mutable.Map[MediaPlayer, MediaView] = new mutable.HashMap[MediaPlayer, MediaView]()
+
+	setLayoutX(zone.x)
+	setLayoutY(zone.y)
+	setMinWidth(zone.width)
+	setMaxWidth(zone.width)
+	setMinHeight(zone.height)
+	setMaxHeight(zone.height)
+
+	def addActivePad(padIndex: PadIndex): Unit = activePlayers.addOne(padIndex)
+
+	def removeActivePad(padIndex: PadIndex): Unit = activePlayers = activePlayers.filter(element => element != padIndex)
+
+	def showMediaPlayer(padIndex: PadIndex, mediaPlayer: MediaPlayer): Unit = {
+		if (!mediaViews.contains(mediaPlayer)) {
+			val mediaView = new MediaView(mediaPlayer)
+			mediaView.setFitWidth(zone.width)
+			mediaView.setFitHeight(zone.height)
+			mediaViews.put(mediaPlayer, mediaView)
+		}
+
+		val mediaView = mediaViews(mediaPlayer)
+		mediaView.setUserData(padIndex)
+		mediaView.setOpacity(1.0)
+
+		if (!getChildren.contains(mediaView)) {
+			val index = activePlayers.indexOf(padIndex)
+			try {
+				getChildren.add(index, mediaView)
+			} catch {
+				case e: Exception =>
+					Logger.error(e)
+					getChildren.add(mediaView)
+			}
+		}
+	}
+
+	def disconnectMediaPlayer(mediaPlayer: MediaPlayer): Unit = {
+		if (mediaViews.contains(mediaPlayer)) {
+			getChildren.remove(mediaViews(mediaPlayer))
+		}
+	}
+
+	def setFadeValue(mediaPlayer: MediaPlayer, value: Double): Unit = {
+		if (mediaViews.contains(mediaPlayer)) {
+			val mediaView = mediaViews(mediaPlayer)
+			mediaView.setOpacity(value)
+		}
+	}
+
+	def highlight(on: Boolean): Unit = {
+		if (on) {
+			setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)))
+		} else {
+			setBackground(null)
+		}
+	}
+
+	override def toString: String = f"MediaPlayerStack: ${getChildren.stream().map(view => f"MediaView: ${view.getUserData}").collect(Collectors.joining(", "))}"
+}
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/settings/ZoneConfiguration.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/settings/ZoneConfiguration.scala
new file mode 100644
index 0000000000000000000000000000000000000000..956a0183c9eafa8245a6565558bf85aeaa176e4c
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/settings/ZoneConfiguration.scala
@@ -0,0 +1,43 @@
+package de.tobias.playpad.plugin.content.settings
+
+import java.util
+import java.util.{List => JavaList}
+
+import de.thecodelabs.storage.settings.annotation.{FilePath, Key}
+import de.tobias.playpad.Displayable
+import javafx.beans.property.{SimpleStringProperty, StringProperty}
+
+@FilePath("players.json")
+class ZoneConfiguration {
+	@Key
+	var zones: JavaList[Zone] = new util.ArrayList[Zone]()
+}
+
+class Zone extends Displayable {
+	@Key
+	private var name: String = _
+	@Key
+	var x: Double = _
+	@Key
+	var y: Double = _
+	@Key
+	var width: Double = _
+	@Key
+	var height: Double = _
+
+	def getName: String = name
+
+	def setName(name: String): Unit = {
+		this.name = name
+		_displayProperty.set(name)
+	}
+
+	private val _displayProperty: StringProperty = new SimpleStringProperty(name)
+
+	override def displayProperty(): StringProperty = {
+		_displayProperty.set(name)
+		_displayProperty
+	}
+
+	override def toString: String = name
+}
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/settings/ZoneSettingsViewController.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/settings/ZoneSettingsViewController.scala
new file mode 100644
index 0000000000000000000000000000000000000000..bae668ff818ef49c8b463df091ccea02bffdb6f4
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/settings/ZoneSettingsViewController.scala
@@ -0,0 +1,134 @@
+package de.tobias.playpad.plugin.content.settings
+
+import de.thecodelabs.utils.ui.scene.input.NumberTextField
+import de.thecodelabs.utils.util.Localization
+import de.tobias.playpad.plugin.content.ContentPluginMain
+import de.tobias.playpad.profile.{Profile, ProfileSettings}
+import de.tobias.playpad.project.Project
+import de.tobias.playpad.viewcontroller.main.IMainViewController
+import de.tobias.playpad.viewcontroller.option.{IProfileReloadTask, ProfileSettingsTabViewController}
+import javafx.application.Platform
+import javafx.fxml.FXML
+import javafx.scene.control.{Button, ListCell, ListView, TextField}
+
+class ZoneSettingsViewController extends ProfileSettingsTabViewController with IProfileReloadTask {
+
+	@FXML
+	var listView: ListView[Zone] = _
+
+	@FXML
+	var nameTextField: TextField = _
+	@FXML
+	var xTextField: NumberTextField = _
+	@FXML
+	var yTextField: NumberTextField = _
+	@FXML
+	var widthTextField: NumberTextField = _
+	@FXML
+	var heightTextField: NumberTextField = _
+
+	@FXML
+	var addButton: Button = _
+	@FXML
+	var removeButton: Button = _
+
+	load("view", "ZoneSettings", Localization.getBundle)
+
+	override def init(): Unit = {
+		listView.setCellFactory((_: ListView[Zone]) => new ListCell[Zone] {
+			override def updateItem(item: Zone, empty: Boolean): Unit = {
+				super.updateItem(item, empty)
+				if (!empty) {
+					textProperty().bind(item.displayProperty())
+				} else {
+					textProperty().unbind()
+					setText("")
+				}
+			}
+		})
+		listView.getSelectionModel.selectedItemProperty().addListener((_, oldValue, newValue) => {
+			val playerViewController = ContentPluginMain.playerViewController
+
+			if (oldValue != null) {
+				saveSettingsToZone(oldValue)
+				playerViewController.highlight(oldValue, on = false)
+			}
+			if (newValue != null) {
+				showSettingsOfZone(newValue)
+				playerViewController.highlight(newValue, on = true)
+			} else {
+				clearTextFields()
+			}
+		})
+	}
+
+	private def saveSettingsToZone(zone: Zone): Unit = {
+		zone.setName(nameTextField.getText)
+		zone.x = xTextField.getText.toDouble
+		zone.y = yTextField.getText.toDouble
+		zone.width = widthTextField.getText.toDouble
+		zone.height = heightTextField.getText.toDouble
+	}
+
+	private def showSettingsOfZone(zone: Zone): Unit = {
+		nameTextField.setText(zone.getName)
+		xTextField.setText(zone.x.toInt.toString)
+		yTextField.setText(zone.y.toInt.toString)
+		widthTextField.setText(zone.width.toInt.toString)
+		heightTextField.setText(zone.height.toInt.toString)
+	}
+
+	private def clearTextFields(): Unit = {
+		nameTextField.setText("")
+		xTextField.setText("")
+		yTextField.setText("")
+		widthTextField.setText("")
+		heightTextField.setText("")
+	}
+
+	// Actions
+	@FXML
+	def onAddHandle(): Unit = {
+		val newConfiguration = new Zone
+		newConfiguration.setName(Localization.getString("plugin.content.player.settings.default_name"))
+
+		getZoneConfiguration.zones.add(newConfiguration)
+		listView.getItems.add(newConfiguration)
+	}
+
+	@FXML
+	def onRemoveHandle(): Unit = {
+		val selectedItem = listView.getSelectionModel.getSelectedItem
+		if (selectedItem != null) {
+			listView.getItems.remove(selectedItem)
+			getZoneConfiguration.zones.remove(selectedItem)
+		}
+	}
+
+	override def loadSettings(settings: Profile): Unit = {
+		listView.getItems.setAll(getZoneConfiguration.zones)
+	}
+
+	override def saveSettings(settings: Profile): Unit = {
+		val selectedItem = listView.getSelectionModel.getSelectedItem
+		if (selectedItem != null) {
+			saveSettingsToZone(selectedItem)
+		}
+	}
+
+	override def needReload(): Boolean = {
+		true
+	}
+
+	override def validSettings(): Boolean = {
+		true
+	}
+
+	override def name(): String = Localization.getString("plugin.content.player.settings")
+
+
+	override def getTask(settings: ProfileSettings, project: Project, controller: IMainViewController): Runnable = () =>
+		Platform.runLater(() => ContentPluginMain.playerViewController.configurePlayers(getZoneConfiguration))
+
+	private def getZoneConfiguration: ZoneConfiguration = Profile.currentProfile().getCustomSettings(ContentPluginMain.zoneConfigurationKey).asInstanceOf[ZoneConfiguration]
+}
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/util/package.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/util/package.scala
new file mode 100644
index 0000000000000000000000000000000000000000..22836f6b9326accde9478b56a7e65861ff3e5fb3
--- /dev/null
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/util/package.scala
@@ -0,0 +1,31 @@
+package de.tobias.playpad.plugin.content
+
+import javafx.collections.ObservableList
+
+package object util {
+
+	implicit class ObservableListExtension[E >: Null](list: ObservableList[E]) {
+		def head: E = {
+			if (list.isEmpty) {
+				return null
+			}
+
+			list.get(0)
+		}
+
+		def apply(index: Int): E = list.get(index)
+
+		def length: Long = list.size()
+
+		def isNotEmpty: Boolean = !list.isEmpty
+
+		def indexWhere(predicate: E => Boolean): Int = {
+			for (i <- 0 until list.size()) {
+				if (predicate(list.get(i))) {
+					return i
+				}
+			}
+			-1
+		}
+	}
+}
diff --git a/PlayWallPlugins/PlayWallPluginMedia/src/main/java/de/tobias/playpad/plugin/media/image/ImagePadContentFactory.java b/PlayWallPlugins/PlayWallPluginMedia/src/main/java/de/tobias/playpad/plugin/media/image/ImagePadContentFactory.java
index 4a9a5ec7b072aa401cb87eea1093050a199b6539..d9c10d492f3725b1bd743b09aab267bfe581046f 100644
--- a/PlayWallPlugins/PlayWallPluginMedia/src/main/java/de/tobias/playpad/plugin/media/image/ImagePadContentFactory.java
+++ b/PlayWallPlugins/PlayWallPluginMedia/src/main/java/de/tobias/playpad/plugin/media/image/ImagePadContentFactory.java
@@ -9,7 +9,7 @@ import javafx.collections.ListChangeListener;
 import javafx.collections.SetChangeListener;
 import javafx.css.PseudoClass;
 import javafx.geometry.Pos;
-import javafx.scene.Node;
+import javafx.scene.Parent;
 import javafx.scene.control.Label;
 import javafx.scene.layout.Pane;
 import javafx.scene.layout.Priority;
@@ -91,7 +91,7 @@ public class ImagePadContentFactory extends PadContentFactory {
 		}
 
 		@Override
-		public Node getNode() {
+		public Parent getNode() {
 			return stackPane;
 		}
 
diff --git a/PlayWallPlugins/PlayWallPluginMedia/src/main/java/de/tobias/playpad/plugin/media/video/VideoPadContentFactory.java b/PlayWallPlugins/PlayWallPluginMedia/src/main/java/de/tobias/playpad/plugin/media/video/VideoPadContentFactory.java
index 96ccd6f3052a05e4ceccc974c486a0708920d2e9..14e2269f4a819ec63df0519285189c2c69be1cae 100644
--- a/PlayWallPlugins/PlayWallPluginMedia/src/main/java/de/tobias/playpad/plugin/media/video/VideoPadContentFactory.java
+++ b/PlayWallPlugins/PlayWallPluginMedia/src/main/java/de/tobias/playpad/plugin/media/video/VideoPadContentFactory.java
@@ -3,18 +3,13 @@ package de.tobias.playpad.plugin.media.video;
 import de.tobias.playpad.pad.Pad;
 import de.tobias.playpad.pad.content.PadContent;
 import de.tobias.playpad.pad.content.PadContentFactory;
+import de.tobias.playpad.pad.preview.PadTextPreview;
 import de.tobias.playpad.pad.view.IPadContentView;
 import de.tobias.playpad.plugin.media.main.impl.MediaPluginImpl;
 import de.tobias.playpad.plugin.media.main.impl.MediaSettingsTabViewController;
 import de.tobias.playpad.viewcontroller.PadSettingsTabViewController;
 import de.tobias.playpad.viewcontroller.option.ProfileSettingsTabViewController;
-import javafx.geometry.Pos;
-import javafx.scene.Node;
-import javafx.scene.control.Label;
 import javafx.scene.layout.Pane;
-import javafx.scene.layout.Priority;
-import javafx.scene.layout.VBox;
-import javafx.scene.text.TextAlignment;
 
 public class VideoPadContentFactory extends PadContentFactory {
 
@@ -31,7 +26,7 @@ public class VideoPadContentFactory extends PadContentFactory {
 
 	@Override
 	public IPadContentView getPadContentPreview(Pad pad, Pane parentNode) {
-		return new VideoContentView(pad, parentNode);
+		return new PadTextPreview(pad, parentNode);
 	}
 
 	@Override
@@ -50,31 +45,4 @@ public class VideoPadContentFactory extends PadContentFactory {
 		return FILE_EXTENSION;
 	}
 
-	private static class VideoContentView implements IPadContentView {
-
-		private final Label nameLabel;
-
-		VideoContentView(Pad pad, Pane parentNode) {
-			nameLabel = new Label();
-			nameLabel.textProperty().bind(pad.nameProperty());
-
-			nameLabel.setWrapText(true);
-			nameLabel.setAlignment(Pos.CENTER);
-			nameLabel.setTextAlignment(TextAlignment.CENTER);
-
-			nameLabel.prefWidthProperty().bind(parentNode.widthProperty());
-			nameLabel.setMaxHeight(Double.MAX_VALUE);
-			VBox.setVgrow(nameLabel, Priority.ALWAYS);
-		}
-
-		@Override
-		public Node getNode() {
-			return nameLabel;
-		}
-
-		@Override
-		public void deInit() {
-			nameLabel.textProperty().unbind();
-		}
-	}
 }
diff --git a/PlayWallPlugins/pom.xml b/PlayWallPlugins/pom.xml
index e633d8b643444f5319297ee50360e08d1722198a..eda2b0ff82e4742bc5850d09101eb204099dc80a 100644
--- a/PlayWallPlugins/pom.xml
+++ b/PlayWallPlugins/pom.xml
@@ -20,6 +20,7 @@
         <module>PlayWallPluginNativeAudio</module>
         <module>PlayWallPluginPlayoutLog</module>
         <module>PlayWallPluginWebAPI</module>
+        <module>PlayWallPluginContentPlayer</module>
     </modules>
 
 </project>
\ No newline at end of file