Skip to content

Commit ac48fd1

Browse files
authored
add subtitle hard link generate in media dir (#194)
* fix special char dir name generate issue and add subtitle hard link generate in media dir * update changelog for pr #194
1 parent 2571c6d commit ac48fd1

File tree

5 files changed

+69
-1
lines changed

5 files changed

+69
-1
lines changed

CHANGELOG.MD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
## Features
66
- 添加剧集URL更新事件,当剧集URL字段更新时,给用户发送邮件通知用户番剧更新了
77
- 添加应用URL前缀环境变量
8+
- 媒体目录会生成与剧集同名的已经上传的ass字幕文件,jellyfin可自动识别
89

910
## Pages
1011
- 用户信息更新页面,支持用户邮箱更新
@@ -16,6 +17,7 @@
1617
- 邮件URL的斜杠重复,导致无法访问资源 #188
1718
- 邮件剧集文件名称不是视频类型的也进行更新了 #188
1819
- 剧集和文件批量匹配失效 #191
20+
- 特殊的番剧名称生成的媒体目录不正确问题,如 `Cyberpunk: Edgerunners` 生成的媒体目录成了 `_J1OWX~4` 原因是目录名不能有英文冒号
1921

2022
## Improvements
2123
- 优化剧集URL更新时通知的代码逻辑,目前在拉取qbittorrent已完成下载的文件任务里,创建服务端对应的文件后,当匹配到对应的剧集URL时,会给用户发送通知邮件

src/main/java/run/ikaros/server/core/repository/FileRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,6 @@ public interface FileRepository extends BaseRepository<FileEntity, Long> {
3838
FileEntity findFileEntityByNameAndTypeAndPlace(String name, FileType type, FilePlace place);
3939

4040
Optional<FileEntity> findByUrlAndStatus(String url, Boolean status);
41+
42+
List<FileEntity> findByNameLike(String name);
4143
}

src/main/java/run/ikaros/server/core/service/FileService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,7 @@ default Long getEpisodeSeqFromName(@Nonnull String name) {
119119

120120
@Nonnull
121121
Optional<FileEntity> findByUrl(@Nonnull String url);
122+
123+
@Nonnull
124+
List<FileEntity> findListByNameLike(@Nonnull String keyword);
122125
}

src/main/java/run/ikaros/server/service/FileServiceImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,13 @@ public Optional<FileEntity> findByUrl(@Nonnull String url) {
445445
return fileRepository.findByUrlAndStatus(url, true);
446446
}
447447

448+
@Nonnull
449+
@Override
450+
public List<FileEntity> findListByNameLike(@Nonnull String keyword) {
451+
AssertUtils.notBlank(keyword, "keyword");
452+
return new ArrayList<>(fileRepository.findByNameLike(StringUtils.addLikeChar(keyword)));
453+
}
454+
448455
private String meringTempChunkFile(String unique, String postfix) throws IOException {
449456
LOGGER.debug("All chunks upload has finish, will start merging files");
450457

src/main/java/run/ikaros/server/service/MediaServiceImpl.java

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Date;
3030
import java.util.List;
3131
import java.util.Optional;
32+
import java.util.stream.Collectors;
3233

3334
@Service
3435
public class MediaServiceImpl implements MediaService {
@@ -75,6 +76,19 @@ private void generateMediaDirBySingleAnimeEntity(@Nonnull AnimeEntity animeEntit
7576
animeDirName += " (" + localDateTime.getYear() + "-" + localDateTime.getMonthValue()
7677
+ "-" + localDateTime.getDayOfMonth() + ")";
7778
}
79+
80+
// remove char \ / : * ? " < > |
81+
animeDirName = animeDirName
82+
.replace("\\", "")
83+
.replace("/", "")
84+
.replace(":", "")
85+
.replace("*", "")
86+
.replace("?", "")
87+
.replace("\"", "")
88+
.replace("<", "")
89+
.replace(">", "")
90+
.replace("|", "");
91+
7892
final String animeDirPath = SystemVarUtils.getCurrentAppMediaDirPath()
7993
+ File.separator + animeDirName;
8094
File animeDir = new File(animeDirPath);
@@ -181,7 +195,7 @@ private void generateMediaDirBySingleSeason(@Nonnull String animeDirPath,
181195
uploadEpFilePath, seasonEntity.getTitle(), episodeEntity.getTitle());
182196
continue;
183197
}
184-
Optional<FileEntity> fileEntityOptional = fileService.findByUrl(url);
198+
Optional<FileEntity> fileEntityOptional = fileService.findByUrl(episodeEntity.getUrl());
185199
String fileName;
186200
if (fileEntityOptional.isPresent()) {
187201
fileName = fileEntityOptional.get().getName();
@@ -220,6 +234,46 @@ private void generateMediaDirBySingleSeason(@Nonnull String animeDirPath,
220234
episodeEntity.getOverview(), episodePlot, String.valueOf(seasonNum),
221235
String.valueOf(seq), String.valueOf(bgmtvId));
222236
}
237+
238+
// link episode subtitle file
239+
List<FileEntity> existsFileEntityList =
240+
fileService.findListByNameLike(fileName.replaceAll(RegexConst.FILE_POSTFIX, ""))
241+
.stream()
242+
.filter(fileEntity -> !fileName.equalsIgnoreCase(fileEntity.getName()))
243+
.toList();
244+
if (!existsFileEntityList.isEmpty()) {
245+
for (FileEntity fileEntity : existsFileEntityList) {
246+
String name = fileEntity.getName();
247+
String postfix = FileUtils.parseFilePostfix(name);
248+
if ("ass".equalsIgnoreCase(postfix)
249+
&& name.contains(
250+
fileName.replaceAll(RegexConst.FILE_POSTFIX, ""))) {
251+
File mediaSubtitleFile =
252+
new File(seasonDirPath + File.separator + name);
253+
File uploadSubtitleFile = new File(
254+
SystemVarUtils.getCurrentAppDirPath()
255+
+ File.separator + fileEntity.getUrl());
256+
if (mediaSubtitleFile.exists()) {
257+
continue;
258+
}
259+
try {
260+
Files.createLink(mediaSubtitleFile.toPath(),
261+
uploadSubtitleFile.toPath());
262+
LOGGER.info(
263+
"create media episode subtitle hard link success, "
264+
+ "link={}, existing={}",
265+
mediaSubtitleFile.getAbsolutePath(),
266+
uploadSubtitleFile.getAbsolutePath());
267+
} catch (IOException e) {
268+
LOGGER.error(
269+
"create media episode subtitle hard link fail, link={}, "
270+
+ "existing={}",
271+
mediaSubtitleFile.getAbsolutePath(),
272+
uploadSubtitleFile.getAbsolutePath());
273+
}
274+
}
275+
}
276+
}
223277
}
224278
}
225279

0 commit comments

Comments
 (0)