Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

YTM App

YouTube Music Downloader - Flutter 크로스플랫폼 앱

📋 목차


개요

YTM App은 YouTube 영상을 고품질 MP3로 다운로드하는 크로스플랫폼 모바일 앱입니다.

지원 플랫폼

플랫폼 지원 배포 방식
Android APK 다운로드, GitHub Releases
iOS TestFlight, 웹앱
Web PWA

스크린샷

┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│     🏠 Home     │  │   ⬇️ Downloads  │  │    🎵 Player    │
├─────────────────┤  ├─────────────────┤  ├─────────────────┤
│                 │  │                 │  │                 │
│  [🔗 URL 입력]  │  │  ▶ Track 1      │  │    ┌───────┐    │
│                 │  │    ████░░ 70%   │  │    │ Album │    │
│  [🔍 검색...]   │  │                 │  │    │  Art  │    │
│                 │  │  ✓ Track 2      │  │    └───────┘    │
│  ─────────────  │  │    완료됨       │  │                 │
│  Recent:        │  │                 │  │  Track Title    │
│  • Stronger     │  │  ▶ Track 3      │  │  Artist Name    │
│  • Heartless    │  │    ██░░░░ 30%   │  │                 │
│  • Gold Digger  │  │                 │  │  ──●───── 2:30  │
│                 │  │                 │  │  ◀◀  ▶  ▶▶     │
└─────────────────┘  └─────────────────┘  └─────────────────┘

기능

핵심 기능

기능 설명
🔗 URL 다운로드 YouTube URL 붙여넣기로 즉시 다운로드
🔍 검색 앱 내에서 YouTube 검색
⬇️ 다운로드 관리 진행률 표시, 큐 관리
🎵 내장 플레이어 다운로드한 음악 바로 재생
📁 라이브러리 다운로드 히스토리 관리

프리미엄 기능

기능 Free Pro
일일 다운로드 3개 무제한
음질 128kbps 320kbps
광고 있음 없음
플레이리스트 다운로드
백그라운드 다운로드

기술 스택

Framework        : Flutter 3.x
State Management : Riverpod 2.x
YouTube API      : youtube_explode_dart
Audio Player     : just_audio + audio_service
Audio Conversion : ffmpeg_kit_flutter
Local Storage    : Hive
HTTP Client      : Dio

프로젝트 구조

ytm-app/
├── lib/
│   ├── main.dart                      # 앱 진입점
│   │
│   ├── core/                          # 핵심 모듈
│   │   ├── api/
│   │   │   └── youtube_api.dart       # YouTube 데이터 조회
│   │   ├── models/
│   │   │   └── track.dart             # Track 데이터 모델
│   │   ├── services/
│   │   │   └── download_service.dart  # 다운로드 + 변환 서비스
│   │   └── utils/                     # 유틸리티 함수
│   │
│   ├── features/                      # 기능별 모듈
│   │   ├── home/                      # 홈 화면
│   │   │   ├── home_screen.dart
│   │   │   └── widgets/
│   │   │       └── recent_downloads.dart
│   │   │
│   │   ├── download/                  # 다운로드 관리
│   │   │   └── download_screen.dart
│   │   │
│   │   ├── player/                    # 음악 플레이어
│   │   │   └── player_screen.dart
│   │   │
│   │   └── settings/                  # 설정
│   │       └── settings_screen.dart
│   │
│   └── shared/                        # 공유 위젯
│       └── widgets/
│
├── assets/                            # 에셋 파일
│   ├── images/
│   └── fonts/
│
├── android/                           # Android 네이티브
├── ios/                               # iOS 네이티브
├── pubspec.yaml                       # 의존성 정의
└── README.md

설치 및 실행

사전 요구사항

  • Flutter SDK 3.0+
  • Dart SDK 3.0+
  • Android Studio / Xcode

설치

# 1. 저장소 클론
git clone https://github.com/shinjadong/ytm-app.git
cd ytm-app

# 2. 의존성 설치
flutter pub get

# 3. Hive 어댑터 생성
flutter pub run build_runner build --delete-conflicting-outputs

# 4. 실행
flutter run

IDE 설정

VS Code 확장:

  • Flutter
  • Dart
  • Flutter Riverpod Snippets

Android Studio 플러그인:

  • Flutter
  • Dart

빌드

Android APK

# Debug APK
flutter build apk --debug

# Release APK
flutter build apk --release

# Split APKs (용량 최적화)
flutter build apk --split-per-abi

출력 경로: build/app/outputs/flutter-apk/

Android App Bundle (Play Store용)

flutter build appbundle --release

iOS

# 시뮬레이터용
flutter build ios --debug

# TestFlight/App Store용 (Mac 필요)
flutter build ios --release

Web

flutter build web --release

아키텍처

상태 관리 (Riverpod)

// Provider 정의
final downloadServiceProvider = Provider((ref) => DownloadService());

final downloadsProvider = StateNotifierProvider<DownloadsNotifier, List<Track>>((ref) {
  return DownloadsNotifier(ref.read(downloadServiceProvider));
});

// 사용
class DownloadScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final downloads = ref.watch(downloadsProvider);
    // ...
  }
}

데이터 흐름

┌─────────────────────────────────────────────────────────┐
│                         UI Layer                         │
│  (HomeScreen, DownloadScreen, PlayerScreen, Settings)   │
└─────────────────────────┬───────────────────────────────┘
                          │ ref.watch() / ref.read()
┌─────────────────────────▼───────────────────────────────┐
│                    State Management                      │
│              (Riverpod Providers/Notifiers)             │
└─────────────────────────┬───────────────────────────────┘
                          │
┌─────────────────────────▼───────────────────────────────┐
│                     Service Layer                        │
│        (YouTubeAPI, DownloadService, AudioService)      │
└─────────────────────────┬───────────────────────────────┘
                          │
┌─────────────────────────▼───────────────────────────────┐
│                      Data Layer                          │
│    (youtube_explode_dart, Hive, Backend API, FFmpeg)    │
└─────────────────────────────────────────────────────────┘

API 연동

백엔드 서버 연결

// lib/core/api/backend_api.dart
class BackendApi {
  static const baseUrl = 'https://api.yourapp.com';

  final Dio _dio = Dio(BaseOptions(
    baseUrl: baseUrl,
    connectTimeout: Duration(seconds: 10),
  ));

  // 토큰 설정
  void setToken(String token) {
    _dio.options.headers['Authorization'] = 'Bearer $token';
  }

  // 영상 정보 조회
  Future<Track> getVideoInfo(String url) async {
    final response = await _dio.get('/api/videos/info',
      queryParameters: {'url': url}
    );
    return Track.fromJson(response.data);
  }

  // 다운로드 요청
  Future<Download> requestDownload(String videoId) async {
    final response = await _dio.post('/api/downloads',
      data: {'video_id': videoId}
    );
    return Download.fromJson(response.data);
  }
}

오프라인 모드 (로컬 처리)

// youtube_explode_dart 직접 사용
class YouTubeApi {
  final YoutubeExplode _yt = YoutubeExplode();

  Future<Track> getVideoInfo(String url) async {
    final video = await _yt.videos.get(url);
    return Track(
      id: video.id.value,
      title: video.title,
      artist: video.author,
      // ...
    );
  }
}

환경 설정

개발 환경

// lib/core/config/env.dart
class Env {
  static const apiUrl = String.fromEnvironment(
    'API_URL',
    defaultValue: 'http://localhost:8000',
  );

  static const isProduction = bool.fromEnvironment('PRODUCTION');
}

빌드 시 환경 변수 전달

flutter run --dart-define=API_URL=https://api.yourapp.com
flutter build apk --dart-define=API_URL=https://api.yourapp.com --dart-define=PRODUCTION=true

테스트

# 유닛 테스트
flutter test

# 통합 테스트
flutter test integration_test/

# 커버리지
flutter test --coverage

라이선스

Proprietary - All rights reserved


관련 저장소

About

YouTube Music Downloader - Flutter cross-platform app

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages