Image Handling
This commit is contained in:
@@ -20,6 +20,9 @@ public class AsyncImageProcessingService {
|
||||
private final StoryService storyService;
|
||||
private final ImageProcessingProgressService progressService;
|
||||
|
||||
@org.springframework.beans.factory.annotation.Value("${storycove.app.public-url:http://localhost:6925}")
|
||||
private String publicUrl;
|
||||
|
||||
@Autowired
|
||||
public AsyncImageProcessingService(ImageService imageService,
|
||||
StoryService storyService,
|
||||
@@ -103,10 +106,54 @@ public class AsyncImageProcessingService {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a URL is external (not from this application).
|
||||
* Returns true if the URL should be downloaded, false if it's already local.
|
||||
*/
|
||||
private boolean isExternalUrl(String url) {
|
||||
return url != null &&
|
||||
(url.startsWith("http://") || url.startsWith("https://")) &&
|
||||
!url.contains("/api/files/images/");
|
||||
if (url == null || url.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip data URLs
|
||||
if (url.startsWith("data:")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip relative URLs (local paths)
|
||||
if (url.startsWith("/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip URLs that are already pointing to our API
|
||||
if (url.contains("/api/files/images/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if URL starts with the public URL (our own domain)
|
||||
if (publicUrl != null && !publicUrl.trim().isEmpty()) {
|
||||
String normalizedUrl = url.trim().toLowerCase();
|
||||
String normalizedPublicUrl = publicUrl.trim().toLowerCase();
|
||||
|
||||
// Remove trailing slash from public URL for comparison
|
||||
if (normalizedPublicUrl.endsWith("/")) {
|
||||
normalizedPublicUrl = normalizedPublicUrl.substring(0, normalizedPublicUrl.length() - 1);
|
||||
}
|
||||
|
||||
if (normalizedUrl.startsWith(normalizedPublicUrl)) {
|
||||
logger.debug("URL is from this application (matches publicUrl): {}", url);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If it's an HTTP(S) URL that didn't match our filters, it's external
|
||||
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||
logger.debug("URL is external: {}", url);
|
||||
return true;
|
||||
}
|
||||
|
||||
// For any other format, consider it non-external (safer default)
|
||||
return false;
|
||||
}
|
||||
|
||||
private ImageService.ContentImageProcessingResult processImagesWithProgress(
|
||||
|
||||
@@ -69,7 +69,10 @@ public class ImageService {
|
||||
|
||||
@Value("${storycove.images.max-file-size:5242880}") // 5MB default
|
||||
private long maxFileSize;
|
||||
|
||||
|
||||
@Value("${storycove.app.public-url:http://localhost:6925}")
|
||||
private String publicUrl;
|
||||
|
||||
public enum ImageType {
|
||||
COVER("covers"),
|
||||
AVATAR("avatars"),
|
||||
@@ -286,9 +289,9 @@ public class ImageService {
|
||||
logger.debug("Found image #{}: {} in tag: {}", imageCount, imageUrl, fullImgTag);
|
||||
|
||||
try {
|
||||
// Skip if it's already a local path or data URL
|
||||
if (imageUrl.startsWith("/") || imageUrl.startsWith("data:")) {
|
||||
logger.debug("Skipping local/data URL: {}", imageUrl);
|
||||
// Skip if it's already a local path, data URL, or from this application
|
||||
if (!isExternalUrl(imageUrl)) {
|
||||
logger.debug("Skipping local/internal URL: {}", imageUrl);
|
||||
matcher.appendReplacement(processedContent, Matcher.quoteReplacement(fullImgTag));
|
||||
continue;
|
||||
}
|
||||
@@ -366,7 +369,7 @@ public class ImageService {
|
||||
Matcher countMatcher = imgPattern.matcher(htmlContent);
|
||||
while (countMatcher.find()) {
|
||||
String imageUrl = countMatcher.group(1);
|
||||
if (!imageUrl.startsWith("/") && !imageUrl.startsWith("data:")) {
|
||||
if (isExternalUrl(imageUrl)) {
|
||||
externalImages.add(imageUrl);
|
||||
}
|
||||
}
|
||||
@@ -384,9 +387,9 @@ public class ImageService {
|
||||
logger.debug("Found image: {} in tag: {}", imageUrl, fullImgTag);
|
||||
|
||||
try {
|
||||
// Skip if it's already a local path or data URL
|
||||
if (imageUrl.startsWith("/") || imageUrl.startsWith("data:")) {
|
||||
logger.debug("Skipping local/data URL: {}", imageUrl);
|
||||
// Skip if it's already a local path, data URL, or from this application
|
||||
if (!isExternalUrl(imageUrl)) {
|
||||
logger.debug("Skipping local/internal URL: {}", imageUrl);
|
||||
matcher.appendReplacement(processedContent, Matcher.quoteReplacement(fullImgTag));
|
||||
continue;
|
||||
}
|
||||
@@ -429,6 +432,56 @@ public class ImageService {
|
||||
return new ContentImageProcessingResult(processedContent.toString(), warnings, downloadedImages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a URL is external (not from this application).
|
||||
* Returns true if the URL should be downloaded, false if it's already local.
|
||||
*/
|
||||
private boolean isExternalUrl(String url) {
|
||||
if (url == null || url.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip data URLs
|
||||
if (url.startsWith("data:")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip relative URLs (local paths)
|
||||
if (url.startsWith("/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip URLs that are already pointing to our API
|
||||
if (url.contains("/api/files/images/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if URL starts with the public URL (our own domain)
|
||||
if (publicUrl != null && !publicUrl.trim().isEmpty()) {
|
||||
String normalizedUrl = url.trim().toLowerCase();
|
||||
String normalizedPublicUrl = publicUrl.trim().toLowerCase();
|
||||
|
||||
// Remove trailing slash from public URL for comparison
|
||||
if (normalizedPublicUrl.endsWith("/")) {
|
||||
normalizedPublicUrl = normalizedPublicUrl.substring(0, normalizedPublicUrl.length() - 1);
|
||||
}
|
||||
|
||||
if (normalizedUrl.startsWith(normalizedPublicUrl)) {
|
||||
logger.debug("URL is from this application (matches publicUrl): {}", url);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If it's an HTTP(S) URL that didn't match our filters, it's external
|
||||
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||
logger.debug("URL is external: {}", url);
|
||||
return true;
|
||||
}
|
||||
|
||||
// For any other format, consider it non-external (safer default)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download an image from a URL and store it locally
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user