Audio and Video nodes for Tiptap based editor working

pull/10/head
Jens Pelzetter 2021-10-19 20:03:34 +02:00
parent 6c18304cd2
commit 773259f89e
12 changed files with 539 additions and 24 deletions

View File

@ -68,7 +68,6 @@ import static org.librecms.CmsConstants.*;
+ "FROM BinaryAsset a " + "FROM BinaryAsset a "
+ "LEFT JOIN a.permissions p " + "LEFT JOIN a.permissions p "
+ "WHERE a.objectId = :assetId " + "WHERE a.objectId = :assetId "
+ "LEFT JOIN a.permissions p "
+ "AND (" + "AND ("
+ " (" + " ("
+ " p.grantee IN :roles " + " p.grantee IN :roles "

View File

@ -337,7 +337,8 @@ public class Assets {
final ProvidesPropertiesForAssetTypeLiteral literal final ProvidesPropertiesForAssetTypeLiteral literal
= new ProvidesPropertiesForAssetTypeLiteral( = new ProvidesPropertiesForAssetTypeLiteral(
asset.getClass()); asset.getClass()
);
final Instance<AssetPropertiesProvider> instance final Instance<AssetPropertiesProvider> instance
= assetPropertiesProviders = assetPropertiesProviders

View File

@ -0,0 +1,155 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.contentsection.rs;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.librecms.assets.BinaryAssetDataService;
import org.librecms.assets.AudioAsset;
import org.librecms.contentsection.Asset;
import org.librecms.contentsection.AssetRepository;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentSectionRepository;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Optional;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Path("/{content-section}/audiomedia")
public class AudioMedia {
private static final Logger LOGGER = LogManager.getLogger(Images.class);
@Inject
private ContentSectionRepository sectionRepo;
@Inject
private AssetRepository assetRepo;
@Inject
private BinaryAssetDataService dataService;
@GET
@Path("/uuid-{uuid}")
public Response getAudioByUuid(
@PathParam("content-section") final String sectionName,
@PathParam("uuid") final String uuid
) {
final Optional<AudioAsset> video = assetRepo
.findByUuidAndType(uuid, AudioAsset.class);
if (video.isPresent()) {
return loadAudio(video.get());
} else {
return Response
.status(Response.Status.NOT_FOUND)
.entity(
String.format(
"The requested video \"%s\" does not exist.",
uuid
)
)
.build();
}
}
@GET
@Path("/{path:^(?!uuid).+$}")
public Response getAudio(
@PathParam("content-section") final String sectionName,
@PathParam("path") final String path
) {
final Optional<ContentSection> section = sectionRepo
.findByLabel(sectionName);
if (!section.isPresent()) {
return Response
.status(Response.Status.NOT_FOUND)
.entity(String.format("No content section \"%s\" available.",
sectionName))
.build();
}
final Optional<Asset> asset = assetRepo.findByPath(
section.get(), path
);
if (asset.isPresent()) {
if (asset.get() instanceof AudioAsset) {
return loadAudio((AudioAsset) asset.get());
} else {
return Response
.status(Response.Status.NOT_FOUND)
.entity(
String.format(
"The asset found at the requested path \"%s\" "
+ "is not an video.",
path
)
)
.build();
}
} else {
return Response
.status(Response.Status.NOT_FOUND)
.entity(
String.format(
"The requested video \"%s\" does not exist.",
path
)
)
.build();
}
}
private Response loadAudio(final AudioAsset video) {
final String mimeType = video.getMimeType().toString();
return Response
.ok()
.entity(
new StreamingOutput() {
@Override
public void write(final OutputStream outputStream)
throws IOException, WebApplicationException {
dataService.copyDataToOutputStream(
video, outputStream
);
}
})
.header("Content-Type", mimeType)
.build();
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.contentsection.rs;
import org.librecms.assets.Bookmark;
import org.librecms.contentsection.Asset;
import java.util.Objects;
import javax.enterprise.context.Dependent;
import javax.json.JsonObjectBuilder;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Dependent
@ProvidesPropertiesForAssetType(Bookmark.class)
public class BookmarkPropertiesProvider implements AssetPropertiesProvider {
@Override
public void addProperties(
final Asset asset, final JsonObjectBuilder builder
) {
Objects.requireNonNull(asset);
Objects.requireNonNull(builder);
if (!(asset instanceof Bookmark)) {
throw new IllegalArgumentException(
String.format(
"\"%s\" only supports assets of type \"%s\". Check "
+ "the qualifier annotation on \"%s\".",
getClass().getName(),
Bookmark.class.getName(),
getClass().getName()
)
);
}
final Bookmark bookmark = (Bookmark) asset;
builder.add("targetUrl", bookmark.getUrl());
}
}

View File

@ -37,10 +37,12 @@ public class ContentSectionsApplication extends Application{
final Set<Class<?>> classes = new HashSet<>(); final Set<Class<?>> classes = new HashSet<>();
classes.add(Assets.class); classes.add(Assets.class);
classes.add(AudioMedia.class);
classes.add(ContentItems.class); classes.add(ContentItems.class);
classes.add(ContentSections.class); classes.add(ContentSections.class);
classes.add(Files.class); classes.add(Files.class);
classes.add(Images.class); classes.add(Images.class);
classes.add(Videos.class);
return classes; return classes;
} }

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.contentsection.rs;
import org.librecms.assets.ExternalAudioAsset;
import org.librecms.contentsection.Asset;
import java.util.Objects;
import javax.enterprise.context.Dependent;
import javax.json.JsonObjectBuilder;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Dependent
@ProvidesPropertiesForAssetType(ExternalAudioAsset.class)
public class ExternalAudioAssetPropertiesProvider extends BookmarkPropertiesProvider {
@Override
public void addProperties(
final Asset asset, final JsonObjectBuilder builder
) {
Objects.requireNonNull(asset);
Objects.requireNonNull(builder);
if (!(asset instanceof ExternalAudioAsset)) {
throw new IllegalArgumentException(
String.format(
"\"%s\" only supports assets of type \"%s\". Check "
+ "the qualifier annotation on \"%s\".",
getClass().getName(),
ExternalAudioAsset.class.getName(),
getClass().getName()
)
);
}
super.addProperties(asset, builder);
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.contentsection.rs;
import org.librecms.assets.ExternalVideoAsset;
import org.librecms.contentsection.Asset;
import java.util.Objects;
import javax.enterprise.context.Dependent;
import javax.json.JsonObjectBuilder;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Dependent
@ProvidesPropertiesForAssetType(ExternalVideoAsset.class)
public class ExternalVideoAssetPropertiesProvider extends BookmarkPropertiesProvider {
@Override
public void addProperties(
final Asset asset, final JsonObjectBuilder builder
) {
Objects.requireNonNull(asset);
Objects.requireNonNull(builder);
if (!(asset instanceof ExternalVideoAsset)) {
throw new IllegalArgumentException(
String.format(
"\"%s\" only supports assets of type \"%s\". Check "
+ "the qualifier annotation on \"%s\".",
getClass().getName(),
ExternalVideoAsset.class.getName(),
getClass().getName()
)
);
}
super.addProperties(asset, builder);
}
}

View File

@ -23,8 +23,6 @@ import org.apache.logging.log4j.Logger;
import org.librecms.assets.BinaryAsset; import org.librecms.assets.BinaryAsset;
import org.librecms.assets.BinaryAssetDataService; import org.librecms.assets.BinaryAssetDataService;
import org.librecms.assets.BinaryAssetRepository; import org.librecms.assets.BinaryAssetRepository;
import org.librecms.contentsection.Asset;
import org.librecms.contentsection.AssetRepository;
import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentSectionRepository; import org.librecms.contentsection.ContentSectionRepository;
@ -51,8 +49,6 @@ public class Files {
private static final Logger LOGGER = LogManager.getLogger(Files.class); private static final Logger LOGGER = LogManager.getLogger(Files.class);
// @Inject
// private AssetRepository assetRepo;
@Inject @Inject
private BinaryAssetRepository binaryAssetRepo; private BinaryAssetRepository binaryAssetRepo;
@ -135,7 +131,7 @@ public class Files {
} }
}) })
.header("ContentType", asset.getMimeType()) .header("Content-Type", asset.getMimeType())
.header( .header(
"Content-Disposition", "Content-Disposition",
String.format( String.format(

View File

@ -23,11 +23,11 @@ import org.librecms.assets.Image;
import org.librecms.contentsection.Asset; import org.librecms.contentsection.Asset;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Objects; import java.util.Objects;
import javax.enterprise.context.Dependent;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.json.JsonObjectBuilder; import javax.json.JsonObjectBuilder;
@ -35,25 +35,29 @@ import javax.json.JsonObjectBuilder;
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@Dependent
@ProvidesPropertiesForAssetType(Image.class) @ProvidesPropertiesForAssetType(Image.class)
public class ImagesPropertiesProvider implements AssetPropertiesProvider { public class ImagesPropertiesProvider implements AssetPropertiesProvider {
@Override @Override
public void addProperties(final Asset asset, public void addProperties(
final JsonObjectBuilder builder) { final Asset asset, final JsonObjectBuilder builder
) {
Objects.requireNonNull(asset); Objects.requireNonNull(asset);
Objects.requireNonNull(builder); Objects.requireNonNull(builder);
if (!(asset instanceof Image)) { if (!(asset instanceof Image)) {
throw new IllegalArgumentException(String throw new IllegalArgumentException(
.format("\"%s\" only supports assets of type \"%s\". Check " String.format(
+ "the qualifier annotation on \"%s\".", "\"%s\" only supports assets of type \"%s\". Check "
getClass().getName(), + "the qualifier annotation on \"%s\".",
Image.class.getName(), getClass().getName(),
getClass().getName())); Image.class.getName(),
getClass().getName()
)
);
} }
final Image image = (Image) asset; final Image image = (Image) asset;
// final byte[] data = image.getData(); // final byte[] data = image.getData();
// final InputStream inputStream = new ByteArrayInputStream(data); // final InputStream inputStream = new ByteArrayInputStream(data);
@ -61,10 +65,10 @@ public class ImagesPropertiesProvider implements AssetPropertiesProvider {
final BufferedImage bufferedImage; final BufferedImage bufferedImage;
try { try {
bufferedImage = ImageIO.read(inputStream); bufferedImage = ImageIO.read(inputStream);
} catch(IOException ex) { } catch (IOException ex) {
throw new UnexpectedErrorException(ex); throw new UnexpectedErrorException(ex);
} }
builder builder
.add("name", image.getDisplayName()) .add("name", image.getDisplayName())
.add("filename", image.getFileName()) .add("filename", image.getFileName())
@ -74,5 +78,5 @@ public class ImagesPropertiesProvider implements AssetPropertiesProvider {
.add("size", image.getDataSize()); .add("size", image.getDataSize());
// .add("size", data.length); // .add("size", data.length);
} }
} }

View File

@ -0,0 +1,155 @@
/*
* Copyright (C) 2021 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.librecms.contentsection.rs;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.librecms.assets.BinaryAssetDataService;
import org.librecms.assets.VideoAsset;
import org.librecms.contentsection.Asset;
import org.librecms.contentsection.AssetRepository;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentSectionRepository;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Optional;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Path("/{content-section}/videos")
public class Videos {
private static final Logger LOGGER = LogManager.getLogger(Images.class);
@Inject
private ContentSectionRepository sectionRepo;
@Inject
private AssetRepository assetRepo;
@Inject
private BinaryAssetDataService dataService;
@GET
@Path("/uuid-{uuid}")
public Response getVideoByUuid(
@PathParam("content-section") final String sectionName,
@PathParam("uuid") final String uuid
) {
final Optional<VideoAsset> video = assetRepo
.findByUuidAndType(uuid, VideoAsset.class);
if (video.isPresent()) {
return loadVideo(video.get());
} else {
return Response
.status(Response.Status.NOT_FOUND)
.entity(
String.format(
"The requested video \"%s\" does not exist.",
uuid
)
)
.build();
}
}
@GET
@Path("/{path:^(?!uuid).+$}")
public Response getVideo(
@PathParam("content-section") final String sectionName,
@PathParam("path") final String path
) {
final Optional<ContentSection> section = sectionRepo
.findByLabel(sectionName);
if (!section.isPresent()) {
return Response
.status(Response.Status.NOT_FOUND)
.entity(String.format("No content section \"%s\" available.",
sectionName))
.build();
}
final Optional<Asset> asset = assetRepo.findByPath(
section.get(), path
);
if (asset.isPresent()) {
if (asset.get() instanceof VideoAsset) {
return loadVideo((VideoAsset) asset.get());
} else {
return Response
.status(Response.Status.NOT_FOUND)
.entity(
String.format(
"The asset found at the requested path \"%s\" "
+ "is not an video.",
path
)
)
.build();
}
} else {
return Response
.status(Response.Status.NOT_FOUND)
.entity(
String.format(
"The requested video \"%s\" does not exist.",
path
)
)
.build();
}
}
private Response loadVideo(final VideoAsset video) {
final String mimeType = video.getMimeType().toString();
return Response
.ok()
.entity(
new StreamingOutput() {
@Override
public void write(final OutputStream outputStream)
throws IOException, WebApplicationException {
dataService.copyDataToOutputStream(
video, outputStream
);
}
})
.header("Content-Type", mimeType)
.build();
}
}

View File

@ -414,7 +414,7 @@ function loadAudioAssets(
selectButton.addEventListener( selectButton.addEventListener(
"click", "click",
(event) => { (event) => {
const audioUrl = `/content-sections/info/audio/uuid-${audioAsset["uuid"]}`; const audioUrl = buildAudioMediaUrl(audioAsset);
node.attrs.audioSrc = audioUrl; node.attrs.audioSrc = audioUrl;
if (audioElem) { if (audioElem) {
audioElem.src = audioUrl; audioElem.src = audioUrl;
@ -443,3 +443,16 @@ function loadAudioAssets(
console.error(error); console.error(error);
}); });
} }
function buildAudioMediaUrl(audioAsset: any) {
switch (audioAsset["type"]) {
case "org.librecms.assets.ExternalAudioAsset":
return audioAsset["properties"]["targetUrl"];
case "org.librecms.assets.AudioAsset":
return `/content-sections/info/audiomedia/uuid-${audioAsset["uuid"]}`;
default:
console.error(`Unknown audio asset type.`);
return "";
}
}

View File

@ -462,7 +462,7 @@ function loadVideos(
selectButton.addEventListener( selectButton.addEventListener(
"click", "click",
(event) => { (event) => {
const videoUrl = `/@contentsections/info/videos/uuid-${video["uuid"]}`; const videoUrl = buildVideoUrl(video);
node.attrs.videoSrc = videoUrl; node.attrs.videoSrc = videoUrl;
if (videoElem) { if (videoElem) {
videoElem.src = videoUrl; videoElem.src = videoUrl;
@ -491,3 +491,15 @@ function loadVideos(
console.error(error); console.error(error);
}); });
} }
function buildVideoUrl(video: any) {
switch (video["type"]) {
case "org.librecms.assets.ExternalVideoAsset":
return video["properties"]["targetUrl"];
case "org.librecms.assets.VideoAsset":
return `/content-sections/info/videos/uuid-${video["uuid"]}`;
default:
console.error(`Unknown video asset type.`);
return "";
}
}