Skip to content

Commit

Permalink
feat: fetch square thumbnail for topic channel videos
Browse files Browse the repository at this point in the history
- when downloading or when fixing thumbnails
ref: #212
  • Loading branch information
MSOB7YY committed Nov 30, 2024
1 parent f3d069e commit 3f3ffda
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 16 deletions.
35 changes: 29 additions & 6 deletions lib/controller/ffmpeg_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:namida/core/constants.dart';
import 'package:namida/core/extensions.dart';
import 'package:namida/core/utils.dart';
import 'package:namida/main.dart';
import 'package:namida/youtube/controller/youtube_info_controller.dart';
import 'package:namida/youtube/widgets/yt_thumbnail.dart';

import 'platform/ffmpeg_executer/ffmpeg_executer.dart';
Expand Down Expand Up @@ -323,21 +324,43 @@ class NamidaFFMPEG {
onMinSizeTrigger: () => null,
);
if (tr == null) continue;
final ytId = tr.youtubeID;
if (ytId.isEmpty) continue;
final videoId = tr.youtubeID;
if (videoId.isEmpty) continue;

File? cachedThumbnail;
File? thumbnailFile;
bool isTempThumbnail = false;
try {
// -- try getting cropped version if required
final channelName = await YoutubeInfoController.utils.getVideoChannelNameAsync(videoId);
const topic = '- Topic';
if (channelName != null && channelName.endsWith(topic)) {
final thumbFilePath = FileParts.joinPath(Directory.systemTemp.path, '$videoId.png');
final thumbFile = await YoutubeInfoController.video.fetchMusicVideoThumbnailToFile(videoId, thumbFilePath);
if (thumbFile != null) {
thumbnailFile = thumbFile;
isTempThumbnail = true;
}
}
} catch (_) {}

cachedThumbnail = await ThumbnailManager.inst.getYoutubeThumbnailAndCache(id: ytId, type: ThumbnailType.video);
thumbnailFile ??= await ThumbnailManager.inst.getYoutubeThumbnailAndCache(
id: videoId,
isImportantInCache: true,
type: ThumbnailType.video,
);

if (cachedThumbnail == null) {
if (thumbnailFile == null) {
currentFailed++;
} else {
final didUpdate = await editAudioThumbnail(
audioPath: filee.path,
thumbnailPath: cachedThumbnail.path,
thumbnailPath: thumbnailFile.path,
);
if (!didUpdate) currentFailed++;

if (isTempThumbnail) {
thumbnailFile.tryDeleting();
}
}

currentOperations[OperationType.ytdlpThumbnailFix]!.value = OperationProgress(
Expand Down
14 changes: 8 additions & 6 deletions lib/controller/indexer_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -839,9 +839,7 @@ class Indexer<T extends Track> {
});

if (updateArtwork) {
imageCache.clear();
imageCache.clearLiveImages();
AudioService.evictArtworkCache();
Indexer.clearMemoryImageCache();
}

tracksMissing.loop((e) => onProgress(false));
Expand Down Expand Up @@ -891,9 +889,7 @@ class Indexer<T extends Track> {
final newTracks = <T>[];

if (artworkWasEdited) {
imageCache.clear();
imageCache.clearLiveImages();
AudioService.evictArtworkCache();
Indexer.clearMemoryImageCache();
}

final finalNewOldTracks = <TrackExtended, TrackExtended?>{};
Expand Down Expand Up @@ -1600,6 +1596,12 @@ class Indexer<T extends Track> {
static SplitArtistGenreConfigsWrapper _createSplitConfig() {
return SplitArtistGenreConfigsWrapper.settings();
}

static void clearMemoryImageCache() {
imageCache.clear();
imageCache.clearLiveImages();
AudioService.evictArtworkCache();
}
}

extension _OrderedInsert<T> on List<T> {
Expand Down
32 changes: 32 additions & 0 deletions lib/youtube/controller/info_controllers/yt_various_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,38 @@ class _YoutubeInfoUtils {
return _tempInfoVideoDurationSeconds[videoId] ??= getStreamInfoSync(videoId)?.durSeconds ?? //
_getVideoStreamResultSync(videoId)?.info?.durSeconds;
}

// ==== async methods ====

Future<StreamInfoItem?> getStreamInfoAsync(String videoId) {
return YoutiPie.cacheBuilder.forStreamInfoItem(videoId: videoId).readAsync();
}

Future<VideoStreamsResult?> _getVideoStreamResultAsync(String videoId) {
return YoutubeInfoController.video.fetchVideoStreams(videoId, forceRequest: false);
}

Future<YoutiPieVideoPageResult?> _getVideoPageResultAsync(String videoId) {
return YoutubeInfoController.video.fetchVideoPage(videoId);
}

Future<String?> getVideoNameAsync(String videoId) async {
String? name = tempVideoInfosFromStreams[videoId]?.title.nullifyEmpty() ?? tempBackupVideoInfo[videoId]?.title.nullifyEmpty();
if (name != null) return name;
final title = await getStreamInfoAsync(videoId).then((value) => value?.title.nullifyEmpty()) ??
await _getVideoStreamResultAsync(videoId).then((value) => value?.info?.title.nullifyEmpty()) ?? //
await _getVideoPageResultAsync(videoId).then((value) => value?.videoInfo?.title.nullifyEmpty());
return _tempInfoTitle[videoId] ??= title;
}

Future<String?> getVideoChannelNameAsync(String videoId) async {
String? name = tempVideoInfosFromStreams[videoId]?.channelName?.nullifyEmpty() ?? tempBackupVideoInfo[videoId]?.channel.nullifyEmpty();
if (name != null) return name;
final channelName = await getStreamInfoAsync(videoId).then((value) => value?.channelName?.nullifyEmpty()) ??
await _getVideoStreamResultAsync(videoId).then((value) => value?.info?.channelName?.nullifyEmpty()) ?? //
await _getVideoPageResultAsync(videoId).then((value) => value?.channelInfo?.title.nullifyEmpty());
return _tempInfoChannelTitle[videoId] ??= channelName;
}
}

extension _StringChecker on String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ class _VideoInfoController {
return res;
}

Future<File?> fetchMusicVideoThumbnailToFile(String videoId, String filePath) {
return YoutiPie.video.fetchMusicVideoThumbnailToFile(id: videoId, filePath: filePath);
}

/// Returns cached streams result if exist. you need to ensure that urls didn't expire ![VideoStreamsResult.hasExpired] before consuming them.
///
/// Enable [bypassJSCheck] if you gurantee using [VideoStreamsResult.info] only.
Expand Down
25 changes: 22 additions & 3 deletions lib/youtube/controller/youtube_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -752,17 +752,36 @@ class YoutubeController {
onInitialAudioFileSize: (initialFileSize) {},
ffmpegTags: config.ffmpegTags,
onAudioFileReady: (audioFile) async {
final thumbnailFile = await ThumbnailManager.inst.getYoutubeThumbnailAndCache(
id: videoID.videoId,
final videoId = videoID.videoId;
File? thumbnailFile;
bool isTempThumbnail = false;
try {
// -- try getting cropped version if required
final channelName = await YoutubeInfoController.utils.getVideoChannelNameAsync(videoId);
const topic = '- Topic';
if (channelName != null && channelName.endsWith(topic)) {
final thumbFilePath = FileParts.joinPath(Directory.systemTemp.path, '$videoId.png');
final thumbFile = await YoutubeInfoController.video.fetchMusicVideoThumbnailToFile(videoId, thumbFilePath);
if (thumbFile != null) {
thumbnailFile = thumbFile;
isTempThumbnail = true;
}
}
} catch (_) {}
thumbnailFile ??= await ThumbnailManager.inst.getYoutubeThumbnailAndCache(
id: videoId,
isImportantInCache: true,
type: ThumbnailType.video,
);
await YTUtils.writeAudioMetadata(
videoId: videoID.videoId,
videoId: videoId,
audioFile: audioFile,
thumbnailFile: thumbnailFile,
tagsMap: config.ffmpegTags,
);
if (isTempThumbnail) {
thumbnailFile?.tryDeleting();
}
},
onVideoFileReady: (videoFile) async {
await NamidaFFMPEG.inst.editMetadata(
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: namida
description: A Beautiful and Feature-rich Music Player, With YouTube & Video Support Built in Flutter
publish_to: "none"
version: 4.7.52-beta+241129207
version: 4.7.6-beta+241130122

environment:
sdk: ">=3.4.0 <4.0.0"
Expand Down

0 comments on commit 3f3ffda

Please sign in to comment.