포스트

chatgpt로 simple flutter code 만들기(14) - 업데이트 진행(2)

1. 캐시 삭제 버튼을 누르면 기존에 사이트 이미지가 삭제되는 것에서 한 가지 기능을 더 추가하기로 함. 모든 drawer의 각 site의 url이 가리키는 썸네일 네트워크 경로를 받아와서 각 site 이미지를 로드해주기로 함.

resetThumbnails()함수로 구현하였음.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Future _clearCache(WidgetRef ref) async {
  try {
    final Directory tempDir = await getTemporaryDirectory();
    final Directory persistentDir = await getApplicationDocumentsDirectory();

    if (tempDir.existsSync()) {
      tempDir.listSync().forEach((FileSystemEntity file) {
        // Check if the file is not in the persistent directory before deleting
        if (!file.path.startsWith(persistentDir.path)) {
          file.deleteSync(recursive: true);
        }
      });
      printDebug("Temporary cache cleared successfully!");
    } else {
      printDebug("Temporary directory does not exist.");
    }

    // Additional code to reset thumbnails after clearing cache
    await resetThumbnails(ref);
  } catch (e) {
    printDebug("Error clearing cache: $e");
  }
}

Future resetThumbnails(WidgetRef ref) async {
  List drawerItems = ref.read(drawerItemsNotifierProvider);

  for (var drawerItem in drawerItems) {
    for (var siteInfo in drawerItem.sites) {
      String? thumbnailUrl;

      // Check if the site URL is a YouTube URL
      if (siteInfo.siteUrl.contains("youtube.com") || siteInfo.siteUrl.contains("youtu.be")) {
        thumbnailUrl = await fetchYouTubeThumbnail(siteInfo.siteUrl);
      } else {
        // Otherwise, fetch the thumbnail from the site URL
        thumbnailUrl = await fetchThumbnailUrl(siteInfo.siteUrl);
      }

      if (thumbnailUrl != null) {
        // Correctly update the imagePath of each siteInfo with the fetched thumbnail URL
        siteInfo.imagePath = thumbnailUrl;
      } else {
        // If no thumbnail URL is found, set to default icon
        siteInfo.imagePath = 'assets/images/default.ico';
      }
    }
  }

  // Update the state with the updated drawer items to reflect the new thumbnails
  ref.read(drawerItemsNotifierProvider.notifier).state = drawerItems;

  // Save the updated drawer items to persistent storage
  await saveDrawerItems(drawerItems);
}

2. 유투브 썸네일을 받아오는 기능에서, 유투브의 '쇼츠'영상일 경우 썸네일을 받아오지 못하고 있는 버그를 발견했음. 그래서 이를 해결하기 위해 검색을 하다가, 미처 발견하지 못한 '라이브'영상의 경우도 고려한 코드를 찾아내었음. 플러터가 널리 쓰이고 있어서 이런 혜택을 누릴 수 있음에 감사함. https://medium.com/flutter-uae/youtube-url-tricks-extracting-video-ids-and-ensuring-validity-in-dart-a19a592baf90

YouTube URL Tricks: Extracting Video IDs and Ensuring Validity in Dart A Comprehensive Guide to YouTube URL Manipulation in Dart A Comprehensive Guide to YouTube URL Manipulation in Dart

다음은 가져온 코드이고,(medium블로그 도움)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Function to extract YouTube video ID from URL
String? extractYouTubeId(String url) {
  if (url.contains(' ')) {
    return null;
  }

  late final Uri uri;
  try {
    uri = Uri.parse(url);
  } catch (e) {
    return null;
  }

  if (!['https', 'http'].contains(uri.scheme)) {
    return null;
  }

  // youtube.com/watch?v=xxxxxxxxxxx
  if (['youtube.com', 'www.youtube.com', 'm.youtube.com'].contains(uri.host) &&
      uri.pathSegments.isNotEmpty &&
      (uri.pathSegments.first == 'watch' || uri.pathSegments.first == 'live') &&
      uri.queryParameters.containsKey('v')) {
    final videoId = uri.queryParameters['v']!;
    return _isValidId(videoId) ? videoId : null;
  }

  // youtu.be/xxxxxxxxxxx
  if (uri.host == 'youtu.be' && uri.pathSegments.isNotEmpty) {
    final videoId = uri.pathSegments.first;
    return _isValidId(videoId) ? videoId : null;
  }

  // www.youtube.com/shorts/xxxxxxxxxxx
  // youtube.com/shorts/xxxxxxxxxxx
  if (uri.host == 'www.youtube.com' || uri.host == 'youtube.com') {
    final pathSegments = uri.pathSegments;
    if (pathSegments.contains('shorts') && pathSegments.length >= 2) {
      final videoId = pathSegments.last;
      return _isValidId(videoId) ? videoId : null;
    }
  }

  // youtube.com/live/xxxxxxxxxxx
  if (['youtube.com', 'www.youtube.com', 'm.youtube.com'].contains(uri.host) &&
      uri.pathSegments.isNotEmpty &&
      uri.pathSegments.first == 'live' && _isValidId(uri.pathSegments.last)) {
    return uri.pathSegments.last;
  }

  return null;
}

bool _isValidId(String id) => RegExp(r'^[_\-a-zA-Z0-9]{11}$').hasMatch(id);

다음은 위 함수를 콜하는 내 코드임. (chatgpt 도움)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Function to fetch YouTube video thumbnail with fallback
Future fetchYouTubeThumbnail(String url) async {
  try {
    String? videoId = extractYouTubeId(url);
    if (videoId == null) {
      return null;
    }

    // Check if the URL is for a YouTube short and adjust the thumbnail URL accordingly
    String baseUrl = url.contains('shorts') ? 'https://i.ytimg.com/vi/' : 'https://img.youtube.com/vi/';
    String thumbnailUrl = '$baseUrl$videoId/maxresdefault.jpg';

    // Check if the URL is valid
    final response = await http.get(Uri.parse(thumbnailUrl));
    if (response.statusCode == 200) {
      return thumbnailUrl;
    } else {
      // Fallback thumbnail if maxresdefault.jpg is not available
      return '$baseUrl$videoId/default.jpg';
    }
  } catch (e) {
    printDebug("Error fetching YouTube thumbnail: $e");
    return null;
  }
}

[영상]

이쯤 되어서 한번 더 배포해야 할 것 같다.

sticker

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.