Skip to content

Commit

Permalink
Feat: 연동 시스템 이미지 링크 추가 구현 Merge
Browse files Browse the repository at this point in the history
Feat: 연동 시스템 이미지 링크 추가 구현
  • Loading branch information
Train0303 authored Nov 8, 2023
2 parents 8e22136 + cae949d commit a406555
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static class BookmarkAddDto {
@NotNull
private Long categoryId;

private String imageData;
private String imageUrl;

private List<String> tags;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void addBookmark(BookmarkRequestDto.BookmarkAddDto bookmarkAddDto, User u
throw new Exception400(BookmarkExceptionStatus.BOOKMARK_ALREADY_EXISTS);
});

String imageUrl = s3ImageClient.base64ImageToS3(bookmarkAddDto.getImageData(), bookmarkAddDto.getBookmarkLink());
String imageUrl = s3ImageClient.base64ImageToS3(bookmarkAddDto.getImageUrl(), bookmarkAddDto.getBookmarkLink());
Bookmark bookmark = bookmarkAddDto.toEntity(category, imageUrl);

bookmarkJpaRepository.save(bookmark);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.kakao.linknamu.thirdparty.googledocs.entity.GooglePage;
import com.kakao.linknamu.thirdparty.googledocs.repository.GooglePageJpaRepository;
import com.kakao.linknamu.thirdparty.googledocs.util.InvalidGoogleDocsApiException;
import com.kakao.linknamu.thirdparty.utils.JsoupResult;
import com.kakao.linknamu.thirdparty.utils.JsoupUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -83,15 +84,11 @@ private List<Bookmark> getLinks(GooglePage googlePage) {
continue;
}

// 링크 항목이 있을 경우 해당 링크의 사이트 제목을 Jsoup 라이브러리를 사용해 받아온다.
// 이를 생성할 북마크의 이름으로 사용한다.
// 만약 해당 데이터를 읽어오지 못하는 경우 link로 저장한다.
String bookmarkName = link;
bookmarkName = jsoupUtils.getTitle(link);
JsoupResult jsoupResult = jsoupUtils.getTitleAndImgUrl(link);
resultBookmarks.add(Bookmark.builder()
.bookmarkLink(link)
.bookmarkName(bookmarkName.length() > 30
? bookmarkName.substring(0, 30) : bookmarkName)
.bookmarkName(jsoupResult.getTitle())
.bookmarkThumbnail(jsoupResult.getImageUrl())
.category(googlePage.getCategory())
.build());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.kakao.linknamu.thirdparty.notion.repository.NotionPageJpaRepository;
import com.kakao.linknamu.thirdparty.notion.util.InvalidNotionApiException;
import com.kakao.linknamu.thirdparty.notion.util.NotionApiUriBuilder;
import com.kakao.linknamu.thirdparty.utils.JsoupResult;
import com.kakao.linknamu.thirdparty.utils.JsoupUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -37,6 +38,9 @@ public class NotionApiBatchService {
private final BookmarkReadService bookmarkReadService;
private final JsoupUtils jsoupUtils;

// 멘션 타입의 노션 페이지 링크일 시, Untitled로 나와 이를 기본 설정으로 변경해서 저장한다.
private static final String DEFAULT_NOTION_PAGE_NAME = "Notion Page";
private static final String DEFAULT_NOTION_IMAGE = "https://www.notion.so/images/meta/default.png";
private static final String NOTION_VERSION = "2022-06-28";

// 한 시간마다 notion API를 통해서 연동한 페이지의 링크를 가져오는 기능 수행
Expand Down Expand Up @@ -123,22 +127,21 @@ private void saveBookmarkOrEmbedLink(
return;
}

String title = url;
JsoupResult jsoupResult = jsoupUtils.getTitleAndImgUrl(url);
if (!caption.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < caption.size(); i++) {
JSONObject captionObject = (JSONObject) caption.get(i);
sb.append(captionObject.get("plain_text"));
title = sb.toString().strip();
}
} else {
title = jsoupUtils.getTitle(url);
jsoupResult.setTitle(sb.toString().strip());
}

resultBookmarks.add(Bookmark.builder()
.bookmarkLink(url)
.bookmarkName(title.length() > 30 ? title.substring(0, 30) : title)
.bookmarkName(jsoupResult.getTitle())
.category(notionPage.getCategory())
.bookmarkThumbnail(jsoupResult.getImageUrl())
.build()
);
}
Expand All @@ -152,21 +155,35 @@ private void saveOtherLink(JSONObject otherTypeObject, Set<Bookmark> resultBookm

for (Object richText : richTexts) {
String href = (String) ((JSONObject) richText).get("href");
String plainText = (String) ((JSONObject) richText).get("plain_text");
String title = (String) ((JSONObject) richText).get("plain_text");
String type = (String) ((JSONObject) richText).get("type");
JsoupResult jsoupResult = new JsoupResult();

if (Objects.nonNull(href)) {
// 만약 한번 연동한 링크라면 더 이상 진행하지 않는다.
if (bookmarkReadService.existByBookmarkLinkAndCategoryId(href, notionPage.getCategory().getCategoryId())) {
continue;
}

if (href.equals(plainText)) {
plainText = jsoupUtils.getTitle(href);
jsoupResult = jsoupUtils.getTitleAndImgUrl(href);

if (!href.equals(title)) {
jsoupResult.setTitle(title);
}

if(type.equals("mention")) {
if( title.equals("Untitled")) {
jsoupResult.setTitle(DEFAULT_NOTION_PAGE_NAME);
} else {
jsoupResult.setTitle(title);
jsoupResult.setImageUrl(DEFAULT_NOTION_IMAGE);
}
}

resultBookmarks.add(Bookmark.builder()
.bookmarkLink(href.startsWith("/") ? "https://www.notion.so" + href : href)
.bookmarkName(plainText.length() > 30 ? plainText.substring(0, 30) : plainText)
.bookmarkName(jsoupResult.getTitle())
.bookmarkThumbnail(jsoupResult.getImageUrl())
.category(notionPage.getCategory())
.build());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.kakao.linknamu.thirdparty.utils;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class JsoupResult {
private String title;
private String imageUrl;

public JsoupResult() {
}

public JsoupResult(String title, String imageUrl) {
this.title = title;
this.imageUrl = imageUrl;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,53 +27,40 @@ public class JsoupUtils {


private static final String DEFAULT_IMAGE = "https://linknamu-image.s3.ap-northeast-2.amazonaws.com/image/default_image.png";
private static final String DEFAULT_TITLE = "추출된 링크";

public String getTitle(String href) {
try {
Connection connection = Jsoup.connect(href)
.userAgent(USER_AGENT)
.timeout(5000);

if (isProxyEnabled) {
connection = connection.proxy(PROXY_HOST, PROXY_PORT);
}
Document doc = connection.get();
Document doc = getDocument(href);
Elements ogTitleTags = doc.select("meta[property=og:title]");
Elements twitterTitleTags = doc.select("meta[name=twitter:title]");
if (!ogTitleTags.isEmpty()) {
return Objects.requireNonNull(ogTitleTags.first()).attr("content");
} else if (!twitterTitleTags.isEmpty()) {
return Objects.requireNonNull(twitterTitleTags.first()).attr("content");
}
return connection.get().title();
return doc.title().equals("") ? DEFAULT_TITLE : doc.title();
} catch (IOException e) {
return href;
return DEFAULT_TITLE;
}
}


public String getImgUrl(String href) {
try {
Connection connection = Jsoup.connect(href)
.userAgent(USER_AGENT)
.timeout(5000);

if (isProxyEnabled) {
connection = connection.proxy(PROXY_HOST, PROXY_PORT);
}
Document doc = connection.get();
Document doc = getDocument(href);
// 이 부분은 이미지 URL을 찾는 방법에 따라 다를 수 있습니다.
// 예를 들어, 이미지 태그를 선택하거나 특정 클래스 또는 속성을 사용할 수 있습니다.
// 아래는 이미지 태그를 선택하는 예제입니다.
Elements imgTags = doc.select("img");
Elements imgOgTags = doc.select("meta[property=og:image]");
Elements imgTwitterTags = doc.select("meta[name=twitter:image]");


if (!imgTags.isEmpty()) {
// 첫 번째 이미지 태그의 'src' 속성을 가져옵니다.
String imageUrl = imgTags.first().attr("src");
System.out.println(imageUrl);
return imageUrl;
if (!imgOgTags.isEmpty()) {
return imgOgTags.first().attr("content");
} else if (!imgTwitterTags.isEmpty()) {
return imgTwitterTags.first().attr("content");
}

// 이미지를 찾지 못한 경우 기본값
return DEFAULT_IMAGE;
} catch (IOException e) {
Expand All @@ -82,4 +69,50 @@ public String getImgUrl(String href) {

}
}

// Jsoup 요청 후 image, title모두 받아오는 메소드
public JsoupResult getTitleAndImgUrl(String href) {
try {
Document doc = getDocument(href);
Elements ogTitleTags = doc.select("meta[property=og:title]");
Elements twitterTitleTags = doc.select("meta[name=twitter:title]");
Elements imgOgTags = doc.select("meta[property=og:image]");
Elements imgTwitterTags = doc.select("meta[name=twitter:image]");

String title;
String imageUrl = DEFAULT_IMAGE;

if (!ogTitleTags.isEmpty()) {
title = ogTitleTags.first().attr("content");
} else if (!twitterTitleTags.isEmpty()) {
title = twitterTitleTags.first().attr("content");
} else {
title = doc.title();
}

if (!imgOgTags.isEmpty()) {
imageUrl = imgOgTags.first().attr("content");
} else if (!imgTwitterTags.isEmpty()) {
imageUrl = imgTwitterTags.first().attr("content");
}

// 이미지 혹은 제목을 찾지 못한 경우 기본값
return new JsoupResult(title.equals("") ? DEFAULT_TITLE : title, imageUrl);
} catch (IOException e) {
// 연결 실패시 기본값
return new JsoupResult(DEFAULT_TITLE, DEFAULT_IMAGE);
}
}

private Document getDocument(String href) throws IOException{
Connection connection = Jsoup.connect(href)
.userAgent(USER_AGENT)
.timeout(5000);

if (isProxyEnabled) {
connection = connection.proxy(PROXY_HOST, PROXY_PORT);
}

return connection.get();
}
}
2 changes: 1 addition & 1 deletion linknamu/src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ cloud:
s3:
bucket: linknamu-image
credentials:
access-key: ${S3_ACCEESS_KEY}
access-key: ${S3_ACCESS_KEY}
secret-key: ${S3_SECRET_KEY}
region:
static: ap-northeast-2
Expand Down
13 changes: 13 additions & 0 deletions linknamu/src/main/resources/application-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ oauth2:
secret: ${NOTION_SECRET}
redirect_uri: ${NOTION_REDIRECT_URI}

cloud:
aws:
s3:
bucket: linknamu-image
credentials:
access-key: ${S3_ACCESS_KEY}
secret-key: ${S3_SECRET_KEY}
region:
static: ap-northeast-2
auto: false
stack:
auto: false

access-jwt-secret-key: ${ACCESS_JWT_SECRET_KEY}
refresh-jwt-secret-key: ${REFRESH_JWT_SECRET_KEY}

Expand Down

0 comments on commit a406555

Please sign in to comment.