MusicPod는 Linux 데스크톱, MacOS 및 Windows용 로컬 음악, 라디오, TV 및 팟캐스트 플레이어입니다. (안드로이드는 계획되어 있지만 언제 구현될지는 아직 예정되지 않았습니다.)
OS | 설치 방법 |
---|---|
리눅스 | 또는 |
윈도우 | 릴리스 페이지 |
맥OS | 릴리스 페이지 |
기계적 인조 인간 | WIP |
특징 | 다크 리눅스 | 라이트 리눅스 | 다크 맥OS | 라이트 맥OS |
---|---|---|---|---|
로컬 오디오 재생 | ||||
메타데이터별로 정렬된 로컬 오디오 찾기 | ||||
icytags와 삽화가 포함된 라디오 방송국을 재생해 보세요! | ||||
팟캐스트 재생 및 다운로드, 안전한 진행, 에피소드 정렬 등을 즐겨보세요! | ||||
비디오 팟캐스트 지원! | ||||
원하는 대로 필터링된 팟캐스트를 찾아보세요 | ||||
원하는 대로 필터링된 라디오 방송국을 찾아보세요 | ||||
다양한 보기 모드 |
앱 아이콘은 Stuart Jaggers가 만들었습니다. Stuart님, 정말 감사합니다!
MusicPod를 Flatpak으로 패키징해 주신 TheShadowOfHassen에게 감사드립니다!
모든 MPV 기여자에게 감사드립니다!
사용하기 매우 쉽고 안정적인 Podcast_search를 만들어 주신 @amugofjava에게 감사드립니다!
뛰어난 성능의 Mediakit 라이브러리와 mpris_service dart 구현을 제공한 @alexmercerind에게 감사드립니다!
사용하기 매우 쉬운 smtc_windows 패키지와 Flutter Discord RPC를 제공해 주신 @KRTirtho에게 감사드립니다.
radiobrowser-api의 dart 구현에 대해 @tomassasovsky에게 감사드립니다!
매우 빠르고 순수한 dart 오디오 메타데이터 리더를 제공해 주신 @ClementBeal에게 감사드립니다!
get_it 및 watch_it을 생성해 주신 @escamoteur에게 감사드립니다. 이로 인해 내 애플리케이션이 더 빨라지고 소스 코드가 더 깔끔해졌습니다!
기여를 매우 환영합니다. 특히 번역. MusicPod를 GitHub 네임스페이스로 포크하고, 컴퓨터에 복제하고, 자신이 명명한 브랜치를 생성하고, 로컬 브랜치에 변경 사항을 커밋하고, 포크에 푸시한 다음 포크에서 이 저장소로 끌어오기 요청을 하세요. 특히 Git 및 GitHub를 처음 접하는 사람들에게는 vscode 확장 GitHub Pull Requests를 추천합니다.
귀하의 언어로 번역하려면 해당 app_xx.arb
파일을 변경하십시오. 여기서 xx
는 귀하의 언어 코드(소문자)입니다. 파일이 아직 존재하지 않는 경우 해당 파일을 생성하고 app_en.arb의 whole
내용을 파일에 복사한 후 번역 값만 변경하고 키는 그대로 두십시오. arb 구문 오류를 방지하려면 Google의 vscode 확장 arb 편집기를 적극 권장합니다. Google 번역 확장 프로그램도 권장됩니다.
오류를 발견하면 문제로 보고하고 최대한 자세히 설명해주세요. 코드를 제공하려면 먼저 이슈를 생성하세요.
테스트 모의는 Mockito를 사용하여 생성됩니다. 서비스 메서드의 서명을 변경한 경우 모의 객체를 다시 생성하려면 build_runner
명령을 실행해야 합니다.
dart run build_runner build
MusicPod는 기본적으로 MPV를 위한 멋진 프런트엔드입니다! 그것이 없으면 여전히 멋져 보이지만 어떤 미디어도 재생되지 않습니다 :D!
MusicPod는 이 반응형 앱의 요구 사항에 가장 적합한 MVVM 아키텍처 패턴을 사용하고 모든 레이어를 분리된 상태로 유지하므로 필요한 경우 하나의 레이어 구현을 교환할 수 있습니다. Flutter 자체에서도 MVVM을 권장합니다.
앱, 플레이어, 검색 및 각 기본 페이지에는 하나 이상의 서비스에 의존하는 하나 이상의 보기 모델인 자체 위젯 세트가 있습니다.
모든 서비스와 ViewModel은 get_it를 통해 느리게 등록됩니다. 즉, di
또는 di
통해 처음 찾을 때까지 인스턴스화되지 않습니다.
흐름도 LR
classDef 뷰 채우기:#0e84207d
classDef viewmodel 채우기:#e9542080
classDef 모델 채우기:#77216f80
보기["`
**보다**
(위젯)
`"]:::view--watchProperty-->ViewModel["`
**뷰모델**
(ChangeNotifier)
`"]:::viewmodel--속성 듣기/가져오기-->모델["`
**(도메인) 모델**
(서비스)
`"]:::모델
ViewModel--알림-->보기
모델--changedProperties.add(true)-->ViewModel
ViewModel은 서비스 로케이터 get_it를 통해 위치하는 생성자를 통해 제공되는 서비스에 대한 종속성을 갖습니다. 이렇게 하면 서비스를 모의 서비스로 대체할 수 있으므로 테스트하기가 쉽습니다.
ViewModel은 ChangeNotifier입니다. 그들은 리스너(구체적인: UI 클래스)를 반응(즉, 재구축)하게 만드는 notifyListener
메소드를 사용할 수 있습니다.
ViewModel은 자신이 의존하는 서비스에 대한 StreamSubscription을 보유합니다. 속성이 비영구적 UI 상태인 경우 ViewModel 내부에 유지됩니다. 그 이상이면 서비스 자산을 얻는 역할에 불과합니다. 따라서 서비스 속성이 변경되면 ViewModel은 PropertiesChanged 스트림을 통해 알림을 받게 되며, UI가 이를 인지하도록 하려면 listen
콜백 내에서 UI(리스너)에 알림을 보냅니다.
이 아키텍처를 구현하기 위한 패키지와 관련하여 저는 공급자에서 Riverpod까지 꽤 많은 여정을 거쳤습니다.
나는 get_it과 watch_it 확장을 사용하여 개인적으로 좋아하는 솔루션을 찾았습니다. 이는 flutter 위젯 트리의 API에 너무 침입하지 않고 이 애플리케이션과 MVVM 아키텍처의 요구 사항에 가장 적합하기 때문입니다.
이렇게 하면 약간의 상용구 코드가 발생하더라도 모든 레이어가 명확하게 분리되고 다시 구현하기 쉽고 따라하기 쉽습니다.
ViewModel의 속성이 변경된 후 위젯을 다시 빌드하려면 watch_it 패키지의 watchPropertyValue
메서드를 사용합니다.
final audio = watchPropertyValue (( PlayerModel m) => m.audio);
ListenableBuilder에 내장된 플러터를 사용할 수도 있지만 이렇게 하면 작업이 더 쉬워집니다.
로컬 표지와 원격 표지는 모두 로드/가져온 후 CoverStore
및 UrlStore
에 캐시됩니다.
로컬 커버를 읽고 라디오 데이터에 대한 원격 커버를 가져오는 것은 추가 두 번째 다트 격리 내에서 발생합니다.
기본 설정은 shared_preferences에 저장됩니다.