| | |
| | | |
| | | @Value("${video.local.path:E:\\yclCode\\DEV_ZHJYZ\\DEV_ZHJYZ\\video-test}") |
| | | private String videoBasePath; |
| | | |
| | | @Value("${image.local.path:E:\\yclCode\\DEV_ZHJYZ\\DEV_ZHJYZ\\images}") |
| | | private String imageBasePath; |
| | | |
| | | private final Map<String, AtomicInteger> convertingTasks = new ConcurrentHashMap<>(); |
| | | private final int MAX_CONCURRENT_CONVERSIONS = 2; |
| | |
| | | } catch (Exception e) { |
| | | log.error("获取随机视频失败", e); |
| | | return Result.error("获取随机视频失败: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | @GetMapping("/random-images") |
| | | @Operation(summary = "获取随机图片地址列表") |
| | | public Result<?> getRandomImages(@RequestParam(defaultValue = "20") Integer count, HttpServletRequest request) { |
| | | try { |
| | | int safeCount = Math.max(1, Math.min(count, 200)); |
| | | File imageDir = new File(imageBasePath); |
| | | if (!imageDir.exists() || !imageDir.isDirectory()) { |
| | | return Result.error("图片目录不存在: " + imageBasePath); |
| | | } |
| | | File[] imageFiles = imageDir.listFiles(file -> file.isFile() && isImageFile(file.getName())); |
| | | if (imageFiles == null || imageFiles.length == 0) { |
| | | return Result.error("目录中没有图片文件"); |
| | | } |
| | | String baseUrl = request.getRequestURL().toString().replace(request.getRequestURI(), ""); |
| | | Random random = new Random(); |
| | | List<String> imageUrls = new ArrayList<>(); |
| | | for (int i = 0; i < safeCount; i++) { |
| | | File selectedImage = imageFiles[random.nextInt(imageFiles.length)]; |
| | | imageUrls.add(baseUrl + "/cube/jyz/video/image/" + selectedImage.getName()); |
| | | } |
| | | return Result.ok(imageUrls); |
| | | } catch (Exception e) { |
| | | log.error("获取随机图片失败", e); |
| | | return Result.error("获取随机图片失败: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | @GetMapping("/image/{imageName:.+}") |
| | | @Operation(summary = "返回本地图片文件") |
| | | public void streamImage(@PathVariable String imageName, HttpServletResponse response) { |
| | | try { |
| | | if (!imageName.matches("^[a-zA-Z0-9._-]+$")) { |
| | | response.sendError(HttpServletResponse.SC_BAD_REQUEST); |
| | | return; |
| | | } |
| | | File imageDir = new File(imageBasePath); |
| | | File imageFile = new File(imageDir, imageName); |
| | | String basePath = imageDir.getCanonicalPath() + File.separator; |
| | | String imagePath = imageFile.getCanonicalPath(); |
| | | if (!imagePath.startsWith(basePath) || !imageFile.exists() || !imageFile.isFile()) { |
| | | response.sendError(HttpServletResponse.SC_NOT_FOUND); |
| | | return; |
| | | } |
| | | String contentType = Files.probeContentType(imageFile.toPath()); |
| | | if (contentType == null || !contentType.startsWith("image/")) { |
| | | contentType = MediaType.IMAGE_JPEG_VALUE; |
| | | } |
| | | response.setHeader("Access-Control-Allow-Origin", "*"); |
| | | response.setHeader("Cache-Control", "max-age=3600"); |
| | | response.setContentType(contentType); |
| | | response.setHeader("Content-Length", String.valueOf(imageFile.length())); |
| | | Files.copy(imageFile.toPath(), response.getOutputStream()); |
| | | response.getOutputStream().flush(); |
| | | } catch (Exception e) { |
| | | log.error("图片读取失败: {}", imageName, e); |
| | | try { |
| | | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
| | | } catch (IOException ignored) { |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | return videoName != null && videoName.toLowerCase(Locale.ROOT).endsWith("_converted.mp4"); |
| | | } |
| | | |
| | | private boolean isImageFile(String fileName) { |
| | | if (fileName == null) { |
| | | return false; |
| | | } |
| | | String lowerName = fileName.toLowerCase(Locale.ROOT); |
| | | return lowerName.endsWith(".jpg") || lowerName.endsWith(".jpeg") || lowerName.endsWith(".png") || lowerName.endsWith(".webp") || lowerName.endsWith(".gif") || lowerName.endsWith(".bmp"); |
| | | } |
| | | |
| | | private boolean waitForConvertedVideo(File outputFile, long waitMs) { |
| | | long deadline = System.currentTimeMillis() + waitMs; |
| | | while (System.currentTimeMillis() < deadline) { |