// Path: src/main/java/eu/goodlike/hls/download/m3u/data/MediaPlaylistData.java
// public final class MediaPlaylistData implements PlaylistData {
// 
//     @Override
//     public CompletableFuture<?> handlePlaylistData() {
//         return writePlaylistToFile()
//                 .thenCompose(actualPlaylistName -> ffmpegProcessor.processFfmpeg(actualPlaylistName, actualPlaylistName));
//     }
// 
//     public CompletableFuture<String> writePlaylistToFile() {
//         String actualPlaylistName = FileUtils.findAvailableName(filename);
//         Path path = Paths.get(actualPlaylistName);
//         try (MediaPlaylistWriter<Path> mediaPlaylistWriter = new FileMediaPlaylistWriter(path)) {
//             mediaPlaylistWriter
//                     .writeStart()
//                     .writeTargetDuration(targetDuration);
// 
//             for (MediaPart mediaPart : mediaParts)
//                 mediaPart.writeInto(mediaPlaylistWriter);
// 
//             mediaPlaylistWriter.writeEnd();
//         } catch (Exception e) {
//             return Futures.failedFuture(e);
//         }
// 
//         return CompletableFuture.completedFuture(actualPlaylistName);
//     }
// 
//     // CONSTRUCTORS
// 
//     @Inject
//     public MediaPlaylistData(@Assisted String filename, @Assisted BigDecimal targetDuration, @Assisted List<MediaPart> mediaParts,
//                              FfmpegProcessor ffmpegProcessor) {
//         Null.check(filename, targetDuration).as("filename, targetDuration");
//         Null.checkList(mediaParts).as("mediaParts");
//         if (mediaParts.isEmpty())
//             throw new IllegalArgumentException("Playlist must have at least one media part");
// 
//         this.filename = filename;
//         this.targetDuration = targetDuration;
//         this.mediaParts = mediaParts;
// 
//         this.ffmpegProcessor = ffmpegProcessor;
//     }
// 
//     // PRIVATE
// 
//     private final String filename;
//     private final BigDecimal targetDuration;
//     private final List<MediaPart> mediaParts;
// 
//     private final FfmpegProcessor ffmpegProcessor;
// 
//     // OBJECT OVERRIDES
// 
//     @Override
//     public String toString() {
//         return MoreObjects.toStringHelper("MediaPlaylistData")
//                 .add("targetDuration", targetDuration)
//                 .add("mediaParts", mediaParts)
//                 .toString();
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (!(o instanceof MediaPlaylistData)) return false;
//         MediaPlaylistData that = (MediaPlaylistData) o;
//         return Objects.equals(targetDuration, that.targetDuration) &&
//                 Objects.equals(mediaParts, that.mediaParts);
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(targetDuration, mediaParts);
//     }
// 
// }
// 
// Path: src/main/java/eu/goodlike/hls/download/m3u/data/MultiMediaPlaylistDataFactory.java
// @SuppressWarnings("BindingAnnotationWithoutInject")
// public interface MultiMediaPlaylistDataFactory {
// 
//     /**
//      * @param videoData playlist data containing video
//      * @param audioData playlist data containing audio
//      * @return new {@link MultiMediaPlaylistData}
//      * @throws NullPointerException if mediaPlaylistDataList is or contains null
//      * @throws IllegalArgumentException if mediaPlaylistDataList is empty
//      */
//     MultiMediaPlaylistData createMultiMediaPlaylistData(@Assisted("video") MediaPlaylistData videoData,
//                                                         @Assisted("audio") MediaPlaylistData audioData);
// 
// }


import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import eu.goodlike.hls.download.m3u.data.MediaPlaylistData;
import eu.goodlike.hls.download.m3u.data.MultiMediaPlaylistDataFactory;
import eu.goodlike.neat.Null;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
package eu.goodlike.hls.download.m3u;



/**
 * Media playlist which has separate video and audio streams; these streams are combined when downloading
 */
public final class MultiMediaPlaylist implements DownloadableMediaPlaylist {

    @Override
    public CompletableFuture<?> download() {
        MediaPlaylistData videoData = videoStream.getMediaPlaylistData();
        MediaPlaylistData audioData = audioStream.getMediaPlaylistData();
        return multiMediaPlaylistDataFactory.createMultiMediaPlaylistData(videoData, audioData).handlePlaylistData();
    }

    @Override
    public String toString() {
        return videoStream.toString();
    }

    // CONSTRUCTORS

    @Inject
    public MultiMediaPlaylist(@Assisted("video") MediaPlaylist videoStream,
                              @Assisted("audio") MediaPlaylist audioStream,
                              MultiMediaPlaylistDataFactory multiMediaPlaylistDataFactory) {
        Null.check(videoStream, audioStream).as("videoStream, audioStream");

        this.videoStream = videoStream;
// Path: src/main/java/eu/goodlike/hls/download/m3u/data/MediaPlaylistData.java
// public final class MediaPlaylistData implements PlaylistData {
// 
//     @Override
//     public CompletableFuture<?> handlePlaylistData() {
//         return writePlaylistToFile()
//                 .thenCompose(actualPlaylistName -> ffmpegProcessor.processFfmpeg(actualPlaylistName, actualPlaylistName));
//     }
// 
//     public CompletableFuture<String> writePlaylistToFile() {
//         String actualPlaylistName = FileUtils.findAvailableName(filename);
//         Path path = Paths.get(actualPlaylistName);
//         try (MediaPlaylistWriter<Path> mediaPlaylistWriter = new FileMediaPlaylistWriter(path)) {
//             mediaPlaylistWriter
//                     .writeStart()
//                     .writeTargetDuration(targetDuration);
// 
//             for (MediaPart mediaPart : mediaParts)
//                 mediaPart.writeInto(mediaPlaylistWriter);
// 
//             mediaPlaylistWriter.writeEnd();
//         } catch (Exception e) {
//             return Futures.failedFuture(e);
//         }
// 
//         return CompletableFuture.completedFuture(actualPlaylistName);
//     }
// 
//     // CONSTRUCTORS
// 
//     @Inject
//     public MediaPlaylistData(@Assisted String filename, @Assisted BigDecimal targetDuration, @Assisted List<MediaPart> mediaParts,
//                              FfmpegProcessor ffmpegProcessor) {
//         Null.check(filename, targetDuration).as("filename, targetDuration");
//         Null.checkList(mediaParts).as("mediaParts");
//         if (mediaParts.isEmpty())
//             throw new IllegalArgumentException("Playlist must have at least one media part");
// 
//         this.filename = filename;
//         this.targetDuration = targetDuration;
//         this.mediaParts = mediaParts;
// 
//         this.ffmpegProcessor = ffmpegProcessor;
//     }
// 
//     // PRIVATE
// 
//     private final String filename;
//     private final BigDecimal targetDuration;
//     private final List<MediaPart> mediaParts;
// 
//     private final FfmpegProcessor ffmpegProcessor;
// 
//     // OBJECT OVERRIDES
// 
//     @Override
//     public String toString() {
//         return MoreObjects.toStringHelper("MediaPlaylistData")
//                 .add("targetDuration", targetDuration)
//                 .add("mediaParts", mediaParts)
//                 .toString();
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (!(o instanceof MediaPlaylistData)) return false;
//         MediaPlaylistData that = (MediaPlaylistData) o;
//         return Objects.equals(targetDuration, that.targetDuration) &&
//                 Objects.equals(mediaParts, that.mediaParts);
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(targetDuration, mediaParts);
//     }
// 
// }
// 
// Path: src/main/java/eu/goodlike/hls/download/m3u/data/MultiMediaPlaylistDataFactory.java
// @SuppressWarnings("BindingAnnotationWithoutInject")
// public interface MultiMediaPlaylistDataFactory {
// 
//     /**
//      * @param videoData playlist data containing video
//      * @param audioData playlist data containing audio
//      * @return new {@link MultiMediaPlaylistData}
//      * @throws NullPointerException if mediaPlaylistDataList is or contains null
//      * @throws IllegalArgumentException if mediaPlaylistDataList is empty
//      */
//     MultiMediaPlaylistData createMultiMediaPlaylistData(@Assisted("video") MediaPlaylistData videoData,
//                                                         @Assisted("audio") MediaPlaylistData audioData);
// 
// }


// Path: src/main/java/eu/goodlike/hls/download/m3u/MultiMediaPlaylist.java
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import eu.goodlike.hls.download.m3u.data.MediaPlaylistData;
import eu.goodlike.hls.download.m3u.data.MultiMediaPlaylistDataFactory;
import eu.goodlike.neat.Null;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

package eu.goodlike.hls.download.m3u;



/**
 * Media playlist which has separate video and audio streams; these streams are combined when downloading
 */
public final class MultiMediaPlaylist implements DownloadableMediaPlaylist {

    @Override
    public CompletableFuture<?> download() {
        MediaPlaylistData videoData = videoStream.getMediaPlaylistData();
        MediaPlaylistData audioData = audioStream.getMediaPlaylistData();
        return multiMediaPlaylistDataFactory.createMultiMediaPlaylistData(videoData, audioData).handlePlaylistData();
    }

    @Override
    public String toString() {
        return videoStream.toString();
    }

    // CONSTRUCTORS

    @Inject
    public MultiMediaPlaylist(@Assisted("video") MediaPlaylist videoStream,
                              @Assisted("audio") MediaPlaylist audioStream,
                              MultiMediaPlaylistDataFactory multiMediaPlaylistDataFactory) {
        Null.check(videoStream, audioStream).as("videoStream, audioStream");

        this.videoStream = videoStream;
        this.audioStream = audioStream;