MediaModel.swift 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*****************************************************************************
  2. * MediaModel.swift
  3. *
  4. * Copyright © 2018 VLC authors and VideoLAN
  5. * Copyright © 2018 Videolabs
  6. *
  7. * Authors: Soomin Lee <bubu@mikan.io>
  8. *
  9. * Refer to the COPYING file of the official project for license.
  10. *****************************************************************************/
  11. protocol MediaModel: MLBaseModel where MLType == VLCMLMedia { }
  12. extension MediaModel {
  13. func append(_ item: VLCMLMedia) {
  14. if !files.contains { $0 == item } {
  15. files.append(item)
  16. }
  17. }
  18. func delete(_ items: [VLCMLObject]) {
  19. do {
  20. for case let media as VLCMLMedia in items {
  21. if let mainFile = media.mainFile() {
  22. try FileManager.default.removeItem(atPath: mainFile.mrl.path)
  23. }
  24. }
  25. medialibrary.reload()
  26. }
  27. catch let error as NSError {
  28. assertionFailure("MediaModel: Delete failed: \(error.localizedDescription)")
  29. }
  30. filterFilesFromDeletion(of: items)
  31. }
  32. }
  33. // MARK: - ViewModel
  34. extension VLCMLMedia {
  35. @objc func mediaDuration() -> String {
  36. return String(format: "%@", VLCTime(int: Int32(duration())))
  37. }
  38. @objc func formatSize() -> String {
  39. return ByteCountFormatter.string(fromByteCount: Int64(mainFile()?.size() ?? 0),
  40. countStyle: .file)
  41. }
  42. @objc func thumbnailImage() -> UIImage? {
  43. var image = UIImage(contentsOfFile: thumbnail()?.path ?? "")
  44. if image == nil
  45. || (!UserDefaults.standard.bool(forKey: kVLCSettingShowThumbnails) && subtype() != .albumTrack)
  46. || (!UserDefaults.standard.bool(forKey: kVLCSettingShowArtworks) && subtype() == .albumTrack) {
  47. let isDarktheme = PresentationTheme.current == PresentationTheme.darkTheme
  48. if subtype() == .albumTrack {
  49. image = isDarktheme ? UIImage(named: "song-placeholder-dark") : UIImage(named: "song-placeholder-white")
  50. } else {
  51. image = isDarktheme ? UIImage(named: "movie-placeholder-dark") : UIImage(named: "movie-placeholder-white")
  52. }
  53. }
  54. return image
  55. }
  56. func accessibilityText(editing: Bool) -> String? {
  57. if editing {
  58. return title + " " + mediaDuration() + " " + formatSize()
  59. }
  60. return title + " " + albumTrackArtistName() + " " + (isNew ? NSLocalizedString("NEW", comment: "") : "")
  61. }
  62. func title() -> String {
  63. if UserDefaults.standard.bool(forKey: kVLCOptimizeItemNamesForDisplay) == true
  64. && ((subtype() == .albumTrack && title.isSupportedAudioMediaFormat())
  65. || (subtype() != .albumTrack && title.isSupportedMediaFormat())) {
  66. return (title as NSString).deletingPathExtension
  67. }
  68. return title
  69. }
  70. }
  71. // MARK: - CoreSpotlight
  72. extension VLCMLMedia {
  73. func coreSpotlightAttributeSet() -> CSSearchableItemAttributeSet {
  74. let attributeSet = CSSearchableItemAttributeSet(itemContentType: "public.audiovisual-content")
  75. attributeSet.title = title
  76. attributeSet.metadataModificationDate = Date()
  77. attributeSet.addedDate = Date()
  78. attributeSet.duration = NSNumber(value: duration() / 1000)
  79. attributeSet.streamable = 0
  80. attributeSet.deliveryType = 0
  81. attributeSet.local = 1
  82. attributeSet.playCount = NSNumber(value: playCount())
  83. if isThumbnailGenerated() == .available {
  84. let image = UIImage(contentsOfFile: thumbnail()?.path ?? "")
  85. attributeSet.thumbnailData = image?.jpegData(compressionQuality: 0.9)
  86. }
  87. attributeSet.codecs = codecs()
  88. attributeSet.languages = languages()
  89. if let audioTracks = audioTracks {
  90. for track in audioTracks {
  91. attributeSet.audioBitRate = NSNumber(value: track.bitrate())
  92. attributeSet.audioChannelCount = NSNumber(value: track.nbChannels())
  93. attributeSet.audioSampleRate = NSNumber(value: track.sampleRate())
  94. }
  95. }
  96. if let albumTrack = albumTrack {
  97. if let genre = albumTrack.genre {
  98. attributeSet.genre = genre.name
  99. }
  100. if let artist = albumTrack.artist {
  101. attributeSet.artist = artist.name
  102. }
  103. attributeSet.audioTrackNumber = NSNumber(value:albumTrack.trackNumber())
  104. if let album = albumTrack.album {
  105. attributeSet.artist = album.title
  106. }
  107. }
  108. return attributeSet
  109. }
  110. func codecs() -> [String] {
  111. var codecs = [String]()
  112. if let videoTracks = videoTracks {
  113. for track in videoTracks {
  114. codecs.append(track.codec)
  115. }
  116. }
  117. if let audioTracks = audioTracks {
  118. for track in audioTracks {
  119. codecs.append(track.codec)
  120. }
  121. }
  122. if let subtitleTracks = subtitleTracks {
  123. for track in subtitleTracks {
  124. codecs.append(track.codec)
  125. }
  126. }
  127. return codecs
  128. }
  129. func languages() -> [String] {
  130. var languages = [String]()
  131. if let videoTracks = videoTracks {
  132. for track in videoTracks where track.language != "" {
  133. languages.append(track.language)
  134. }
  135. }
  136. if let audioTracks = audioTracks {
  137. for track in audioTracks where track.language != "" {
  138. languages.append(track.language)
  139. }
  140. }
  141. if let subtitleTracks = subtitleTracks {
  142. for track in subtitleTracks where track.language != "" {
  143. languages.append(track.language)
  144. }
  145. }
  146. return languages
  147. }
  148. func updateCoreSpotlightEntry() {
  149. if !KeychainCoordinator.passcodeLockEnabled {
  150. let groupIdentifier = ProcessInfo.processInfo.environment["GROUP_IDENTIFIER"]
  151. let item = CSSearchableItem(uniqueIdentifier: "\(identifier())", domainIdentifier: groupIdentifier, attributeSet: coreSpotlightAttributeSet())
  152. CSSearchableIndex.default().indexSearchableItems([item], completionHandler: nil)
  153. }
  154. }
  155. }
  156. // MARK: - Search
  157. extension VLCMLMedia: SearchableMLModel {
  158. func contains(_ searchString: String) -> Bool {
  159. return title.lowercased().contains(searchString)
  160. }
  161. }
  162. extension VLCMLMedia {
  163. func albumTrackArtistName() -> String {
  164. guard let albumTrack = albumTrack else {
  165. return NSLocalizedString("UNKNOWN_ARTIST", comment: "")
  166. }
  167. return albumTrack.albumArtistName()
  168. }
  169. }