Skip to content

Commit

Permalink
#297: 유튜브 뮤직앱에서 공유하기로 가져온 데이터를 파싱한 노래이름, 아티스트이름으로 음악검색 비즈니스로직 실행 및 M…
Browse files Browse the repository at this point in the history
…usic Array 첫번째 인덱스값 앨범커버, 노래이름, 아티스트이름 UI에 표시
  • Loading branch information
joseph704 committed Aug 14, 2024
1 parent 858da94 commit 9774386
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 2 deletions.
70 changes: 69 additions & 1 deletion StreetDrop/ShareExtension/View/ShareViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ final class ShareViewController: SLComposeServiceViewController {
final class ShareViewController: UIViewController {
private let viewModel: ShareViewModel = .init()
private let disposeBag: DisposeBag = .init()
private let sharedMusicKeyWordEvent: PublishRelay<String> = .init()

override func isContentValid() -> Bool {
return true
Expand Down Expand Up @@ -121,12 +122,20 @@ final class ShareViewController: UIViewController {
super.viewDidLoad()
bindViewModel()
configureUI()

// 공유된 데이터 가져오기
guard let extensionItem = extensionContext?.inputItems.first as? NSExtensionItem else { return }
handleExtensionItem(extensionItem)
}
}
}

private extension ShareViewController {
func bindViewModel() {
let input: ShareViewModel.Input = .init(viewDidLoadEvent: .just(Void()))
let input: ShareViewModel.Input = .init(
viewDidLoadEvent: .just(Void()),
sharedMusicKeyWordEvent: sharedMusicKeyWordEvent.asObservable()
)
let output: ShareViewModel.Output = viewModel.convert(
input: input,
disposedBag: disposeBag
Expand All @@ -137,6 +146,14 @@ private extension ShareViewController {
owner.villageNameLabel.text = villageName
}
.disposed(by: disposeBag)

output.showSearchedMusic
.bind(with: self) { owner, music in
owner.albumCoverImageView.kf.setImage(with: URL(string: music.albumImage))
owner.songNameLabel.text = music.songName
owner.artistNameLabel.text = music.artistName
}
.disposed(by: disposeBag)
}

func configureUI() {
Expand Down Expand Up @@ -198,5 +215,56 @@ private extension ShareViewController {
}
}
}

// MARK: - Handle Shared Data
private extension ShareViewController {
func handleExtensionItem(_ extensionItem: NSExtensionItem) {
// ExtensionItem에서 ContentText 추출
guard let sharedTextItem = extensionItem.attributedContentText,
let videoID = extractVideoID(from: sharedTextItem.string) else { return }

fetchVideoDetails(videoID: videoID) { [weak self] songName, artistName in
self?.sharedMusicKeyWordEvent.accept("\(songName ?? "")-\(artistName ?? "")")
}
}

func fetchVideoDetails(videoID: String, completion: @escaping (String?, String?) -> Void) {
let apiKey = "AIzaSyDHsdIcuAK98-EW9UueCeF6g4iYiap7bmA" // YouTube Data API 키를 여기에 입력하세요
let urlString = "https://www.googleapis.com/youtube/v3/videos?id=\(videoID)&key=\(apiKey)&part=snippet"

guard let url = URL(string: urlString) else {
completion(nil, nil)
return
}

let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else {
completion(nil, nil)
return
}

do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let items = json["items"] as? [[String: Any]],
let snippet = items.first?["snippet"] as? [String: Any] {
let title = snippet["title"] as? String
let channelTitle = snippet["channelTitle"] as? String
completion(title, channelTitle)
} else {
completion(nil, nil)
}
} catch {
completion(nil, nil)
}
}
task.resume()
}

func extractVideoID(from url: String) -> String? {
guard let urlComponents = URLComponents(string: url),
let queryItems = urlComponents.queryItems else {
return nil
}
return queryItems.first(where: { $0.name == "v" })?.value
}
}
21 changes: 20 additions & 1 deletion StreetDrop/ShareExtension/ViewModel/ShareViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,18 @@ final class ShareViewModel: NSObject, ShareViewModelType {

struct Input {
let viewDidLoadEvent: Observable<Void>
let sharedMusicKeyWordEvent: Observable<String>
}

struct Output {

fileprivate let showVillageNameRelay: PublishRelay<String> = .init()
var showVillageName: Observable<String> {
showVillageNameRelay.asObservable()
}
fileprivate let showSearchedMusicRelay: PublishRelay<Music> = .init()
var showSearchedMusic: Observable<Music> {
showSearchedMusicRelay.asObservable()
}
}

func convert(input: Input, disposedBag: DisposeBag) -> Output {
Expand All @@ -49,6 +53,21 @@ final class ShareViewModel: NSObject, ShareViewModelType {
}
.disposed(by: disposedBag)

input.sharedMusicKeyWordEvent
.bind(with: self) { owner, sharedMusicKeyWord in
owner.searchMusicUsecase.searchMusic(keyword: sharedMusicKeyWord)
.subscribe(with: self) { owner, musicList in
guard let firstMusic = musicList.first else {
// TODO: 요셉, 검색된 음악 없다는 이벤트 view에 전달
return
}
owner.output.showSearchedMusicRelay.accept(firstMusic)
} onFailure: { owner, error in

}
.disposed(by: disposedBag)
}
.disposed(by: disposedBag)

return output
}
Expand Down

0 comments on commit 9774386

Please sign in to comment.