Skip to content

Commit

Permalink
#212 implement avatar repository for replaement of avatardao
Browse files Browse the repository at this point in the history
  • Loading branch information
kagemomiji committed Aug 29, 2023
1 parent 1d76c91 commit 2864307
Show file tree
Hide file tree
Showing 47 changed files with 1,360 additions and 701 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,7 @@
*/
package org.airsonic.player.ajax;

import org.airsonic.player.domain.AvatarScheme;
import org.airsonic.player.domain.MediaFile;
import org.airsonic.player.domain.PlayStatus;
import org.airsonic.player.domain.Player;
import org.airsonic.player.domain.UserSettings;
import org.airsonic.player.service.SettingsService;
import org.airsonic.player.util.StringUtil;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;

import java.util.UUID;

Expand Down Expand Up @@ -134,57 +126,4 @@ public long getMinutesAgo() {
public PlayStatus fromPlayStatus() {
return playStatus;
}

public static NowPlayingInfo createForBroadcast(PlayStatus status, SettingsService settingsService) {
String url = "";// NetworkService.getBaseUrl(request);

Player player = status.getPlayer();
MediaFile mediaFile = status.getMediaFile();
if (mediaFile == null) {
return null;
}
String username = player.getUsername();
if (username == null) {
return null;
}
long minutesAgo = status.getMinutesAgo();
if (minutesAgo > 60) {
return null;
}
UserSettings userSettings = settingsService.getUserSettings(username);
if (!userSettings.getNowPlayingAllowed()) {
return null;
}

String artist = mediaFile.getArtist();
String title = mediaFile.getTitle();
String streamUrl = url + "stream?player=" + player.getId() + "&id=" + mediaFile.getId();
String albumUrl = url + "main.view?id=" + mediaFile.getId();
String lyricsUrl = null;
if (!mediaFile.isVideo()) {
lyricsUrl = url + "lyrics.view?artistUtf8Hex=" + StringUtil.utf8HexEncode(artist) + "&songUtf8Hex="
+ StringUtil.utf8HexEncode(title);
}
String coverArtUrl = url + "coverArt.view?size=60&id=" + mediaFile.getId();

String avatarUrl = null;
if (userSettings.getAvatarScheme() == AvatarScheme.SYSTEM) {
avatarUrl = url + "avatar.view?id=" + userSettings.getSystemAvatarId();
} else if (userSettings.getAvatarScheme() == AvatarScheme.CUSTOM
&& settingsService.getCustomAvatar(username) != null) {
avatarUrl = url + "avatar.view?usernameUtf8Hex=" + StringUtil.utf8HexEncode(username);
}

String tooltip = StringEscapeUtils.escapeHtml(artist) + " – " + StringEscapeUtils.escapeHtml(title);

if (StringUtils.isNotBlank(player.getName())) {
username += "@" + player.getName();
}
artist = StringEscapeUtils.escapeHtml(StringUtils.abbreviate(artist, 25));
title = StringEscapeUtils.escapeHtml(StringUtils.abbreviate(title, 25));
username = StringEscapeUtils.escapeHtml(StringUtils.abbreviate(username, 25));

return new NowPlayingInfo(status.getTransferId(), player.getId(), mediaFile.getId(), username, artist, title,
tooltip, streamUrl, albumUrl, lyricsUrl, coverArtUrl, avatarUrl, minutesAgo, status);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.airsonic.player.ajax;

import org.airsonic.player.domain.UserSettings;
import org.airsonic.player.service.SettingsService;
import org.airsonic.player.service.PersonalSettingsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.annotation.SendToUser;
Expand All @@ -13,34 +13,32 @@
@Controller
@MessageMapping("/settings")
public class UserSettingsWSController {

@Autowired
private SettingsService settingsService;
private PersonalSettingsService personalSettingsService;

@MessageMapping("/sidebar")
@SendToUser
public boolean setShowSideBar(Principal p, boolean show) {
UserSettings userSettings = settingsService.getUserSettings(p.getName());
UserSettings userSettings = personalSettingsService.getUserSettings(p.getName());
if (show != userSettings.getShowSideBar()) {
userSettings.setShowSideBar(show);
userSettings.setChanged(Instant.now());
settingsService.updateUserSettings(userSettings);
personalSettingsService.updateUserSettings(userSettings);
}
return show;
}

@MessageMapping("/viewAsList")
@SendToUser
public boolean setViewAsList(Principal p, boolean viewAsList) {
UserSettings userSettings = settingsService.getUserSettings(p.getName());
UserSettings userSettings = personalSettingsService.getUserSettings(p.getName());
if (viewAsList != userSettings.getViewAsList()) {
userSettings.setViewAsList(viewAsList);
userSettings.setChanged(Instant.now());
settingsService.updateUserSettings(userSettings);
personalSettingsService.updateUserSettings(userSettings);
}
return viewAsList;
}

public void setSettingsService(SettingsService settingsService) {
this.settingsService = settingsService;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
package org.airsonic.player.controller;

import org.airsonic.player.domain.Avatar;
import org.airsonic.player.domain.AvatarScheme;
import org.airsonic.player.domain.UserSettings;
import org.airsonic.player.service.SettingsService;
import org.airsonic.player.service.PersonalSettingsService;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
Expand All @@ -43,11 +41,13 @@
@RequestMapping("/avatar")
public class AvatarController {

@Autowired
private SettingsService settingsService;
@Autowired
private ResourceLoader loader;

@Autowired
private PersonalSettingsService personalSettingsService;


/**
private long getLastModified(Avatar avatar, String username) {
long result = avatar == null ? -1L : avatar.getCreatedDate().toEpochMilli();
Expand All @@ -68,7 +68,12 @@ public void handleRequest(
@RequestParam(defaultValue = "false") boolean forceCustom,
HttpServletResponse response) throws Exception {

Avatar avatar = getAvatar(id, username, forceCustom);
if (id == null && username == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}

Avatar avatar = personalSettingsService.getAvatar(id, username, forceCustom);

if (avatar == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
Expand All @@ -82,25 +87,4 @@ public void handleRequest(
}
IOUtils.copy(res.getInputStream(), response.getOutputStream());
}

private Avatar getAvatar(Integer id, String username, boolean forceCustom) {

if (id != null) {
return settingsService.getSystemAvatar(id);
}

if (username == null) {
return null;
}

UserSettings userSettings = settingsService.getUserSettings(username);
if (userSettings.getAvatarScheme() == AvatarScheme.CUSTOM || forceCustom) {
return settingsService.getCustomAvatar(username);
}
if (userSettings.getAvatarScheme() == AvatarScheme.NONE) {
return null;
}
return settingsService.getSystemAvatar(userSettings.getSystemAvatarId());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,8 @@
package org.airsonic.player.controller;

import com.google.re2j.Pattern;
import org.airsonic.player.config.AirsonicHomeConfig;
import org.airsonic.player.domain.Avatar;
import org.airsonic.player.service.PersonalSettingsService;
import org.airsonic.player.service.SecurityService;
import org.airsonic.player.service.SettingsService;
import org.airsonic.player.util.FileUtil;
import org.airsonic.player.util.StringUtil;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -39,16 +33,8 @@
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

Expand All @@ -62,15 +48,11 @@
public class AvatarUploadController {

private static final Logger LOG = LoggerFactory.getLogger(AvatarUploadController.class);
private static final int MAX_AVATAR_SIZE = 64;

@Autowired
private SettingsService settingsService;
@Autowired
private SecurityService securityService;
@Autowired
private AirsonicHomeConfig homeConfig;

private PersonalSettingsService personalSettingsService;

@PostMapping
protected ModelAndView handleRequestInternal(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws Exception {
Expand All @@ -81,62 +63,15 @@ protected ModelAndView handleRequestInternal(@RequestParam("file") MultipartFile
if (!file.isEmpty()) {
String filename = file.getOriginalFilename();
Pattern pattern = Pattern.compile("\\.+/");
createAvatar(pattern.matcher(filename).replaceAll(""), file.getBytes(), username, map);
map = personalSettingsService.createCustomAvatar(pattern.matcher(filename).replaceAll(""), file.getBytes(), username);
} else {
map.put("error", new Exception("Missing file."));
LOG.warn("Failed to upload personal image. No file specified.");
}

map.put("username", username);
map.put("avatar", settingsService.getCustomAvatar(username));
map.put("avatar", personalSettingsService.getCustomAvatar(username));
return new ModelAndView("avatarUploadResult", "model", map);
}

/**
* Creates an avatar image from the given data.
*
* @param fileName the file name of the image.
* @param data the image data.
* @param username the username.
* @param map the model.
*/
private void createAvatar(String fileName, byte[] data, String username, Map<String, Object> map) {

BufferedImage image;
try {
image = ImageIO.read(new ByteArrayInputStream(data));
if (image == null) {
throw new IOException("Failed to decode incoming image: " + fileName + " (" + data.length + " bytes).");
}
int width = image.getWidth();
int height = image.getHeight();
String mimeType = StringUtil.getMimeType(FilenameUtils.getExtension(fileName));
Path folder = homeConfig.getAirsonicHome().resolve("avatars").resolve(username);
Files.createDirectories(folder);
Path fileOnDisk = folder.resolve(fileName + "." + StringUtils.substringAfter(mimeType, "/"));
// Scale down image if necessary.
if (width > MAX_AVATAR_SIZE || height > MAX_AVATAR_SIZE) {
double scaleFactor = MAX_AVATAR_SIZE / (double)Math.max(width, height);
height = (int) (height * scaleFactor);
width = (int) (width * scaleFactor);
image = CoverArtController.scale(image, width, height);
mimeType = StringUtil.getMimeType("jpeg");
fileOnDisk = folder.resolve(fileName + ".jpeg");
ImageIO.write(image, "jpeg", fileOnDisk.toFile());

map.put("resized", true);
} else {
Files.copy(new ByteArrayInputStream(data), fileOnDisk, StandardCopyOption.REPLACE_EXISTING);
}
Avatar avatar = new Avatar(0, fileName, Instant.now(), mimeType, width, height, fileOnDisk);
settingsService.setCustomAvatar(avatar, username);
LOG.info("Created avatar '{}' ({} bytes) for user {}", fileName, FileUtil.size(fileOnDisk), username);

} catch (IOException x) {
LOG.warn("Failed to upload personal image", x);
map.put("error", x);
}
}


}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.airsonic.player.controller;

import org.airsonic.player.service.SettingsService;
import org.airsonic.player.service.PersonalSettingsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -16,12 +16,12 @@
@RequestMapping("/bookmarks")
public class BookmarksController {
@Autowired
private SettingsService settingsService;
private PersonalSettingsService personalSettingsService;

@GetMapping
public ModelAndView doGet(Principal user, HttpServletRequest request) {
return new ModelAndView("bookmarks", "model",
Map.of("initialPaginationSize",
settingsService.getUserSettings(user.getName()).getPaginationSizeBookmarks()));
personalSettingsService.getUserSettings(user.getName()).getPaginationSizeBookmarks()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.airsonic.player.service.*;
import org.airsonic.player.service.metadata.JaudiotaggerParser;
import org.airsonic.player.util.FileUtil;
import org.airsonic.player.util.ImageUtil;
import org.airsonic.player.util.StringUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
Expand Down Expand Up @@ -234,7 +235,7 @@ private void sendFallback(Integer size, HttpServletResponse response) throws IOE
try (InputStream in = getClass().getResourceAsStream("default_cover.jpg")) {
BufferedImage image = ImageIO.read(in);
if (size != null) {
image = scale(image, size, size);
image = ImageUtil.scale(image, size, size);
}
ImageIO.write(image, "jpeg", response.getOutputStream());
}
Expand Down Expand Up @@ -355,34 +356,6 @@ private synchronized Path getImageCacheDirectory(int size) {
return dir;
}

public static BufferedImage scale(BufferedImage image, int width, int height) {
int w = image.getWidth();
int h = image.getHeight();
BufferedImage thumb = image;

// For optimal results, use step by step bilinear resampling - halfing the size at each step.
do {
w /= 2;
h /= 2;
if (w < width) {
w = width;
}
if (h < height) {
h = height;
}

BufferedImage temp = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = temp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(thumb, 0, 0, temp.getWidth(), temp.getHeight(), null);
g2.dispose();

thumb = temp;
} while (w != width);

return thumb;
}


private abstract class CoverArtRequest {
Expand Down Expand Up @@ -420,7 +393,7 @@ public BufferedImage createImage(int size) {
if (bimg == null) {
reason = "ImageIO.read";
} else {
return scale(bimg, size, size);
return ImageUtil.scale(bimg, size, size);
}
}
LOG.warn("Failed to process cover art {}: {} failed", coverArt, reason);
Expand Down
Loading

0 comments on commit 2864307

Please sign in to comment.