@roitium/expo-orpheus 0.9.4 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'ExpoOrpheus'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.description = package['description']
10
+ s.license = package['license']
11
+ s.author = package['author']
12
+ s.homepage = package['homepage']
13
+ s.platforms = {
14
+ :ios => '15.1',
15
+ :tvos => '15.1'
16
+ }
17
+ s.swift_version = '5.9'
18
+ s.source = { git: 'https://github.com/bbplayer-app/orpheus.git' }
19
+ s.static_framework = true
20
+
21
+ s.dependency 'ExpoModulesCore'
22
+
23
+ # Swift/Objective-C compatibility
24
+ s.pod_target_xcconfig = {
25
+ 'DEFINES_MODULE' => 'YES'
26
+ }
27
+
28
+ s.source_files = "**/*.{h,m,swift}"
29
+ end
@@ -0,0 +1,228 @@
1
+ import ExpoModulesCore
2
+
3
+ public class ExpoOrpheusModule: Module {
4
+
5
+ private func setupEventListeners() {
6
+ let manager = OrpheusPlayerManager.shared
7
+
8
+ manager.onPlaybackStateChanged = { [weak self] state in
9
+ self?.sendEvent("onPlaybackStateChanged", ["state": state.rawValue])
10
+ }
11
+
12
+ manager.onTrackStarted = { [weak self] trackId, reason in
13
+ self?.sendEvent("onTrackStarted", ["trackId": trackId, "reason": reason.rawValue])
14
+ }
15
+
16
+ manager.onPositionUpdate = { [weak self] position, duration, buffered in
17
+ self?.sendEvent("onPositionUpdate", [
18
+ "position": position,
19
+ "duration": duration,
20
+ "buffered": buffered
21
+ ])
22
+ }
23
+
24
+ OrpheusDownloadManager.shared.onDownloadUpdated = { [weak self] task in
25
+ self?.sendEvent("onDownloadUpdated", [
26
+ "id": task.id,
27
+ "state": task.state.rawValue,
28
+ "percentDownloaded": task.percentDownloaded,
29
+ "bytesDownloaded": task.bytesDownloaded,
30
+ "contentLength": task.contentLength
31
+ ])
32
+ }
33
+
34
+ manager.onPlayerError = { [weak self] errorMsg in
35
+ self?.sendEvent("onPlayerError", ["error": errorMsg])
36
+ }
37
+
38
+ manager.onIsPlayingChanged = { [weak self] isPlaying in
39
+ self?.sendEvent("onIsPlayingChanged", ["status": isPlaying])
40
+ }
41
+ }
42
+
43
+ public func definition() -> ModuleDefinition {
44
+ Name("Orpheus")
45
+
46
+ // Events
47
+ Events(
48
+ "onPlaybackStateChanged",
49
+ "onTrackStarted",
50
+ "onTrackFinished",
51
+ "onPlayerError",
52
+ "onPositionUpdate",
53
+ "onIsPlayingChanged",
54
+ "onDownloadUpdated",
55
+ "onPlaybackSpeedChanged"
56
+ )
57
+
58
+ OnCreate {
59
+ self.setupEventListeners()
60
+ }
61
+
62
+ // MARK: - Preferences
63
+
64
+ Property("restorePlaybackPositionEnabled")
65
+ .get { GeneralStorage.shared.isRestoreEnabled }
66
+ .set { GeneralStorage.shared.isRestoreEnabled = $0 }
67
+
68
+ Property("loudnessNormalizationEnabled")
69
+ .get { GeneralStorage.shared.isLoudnessNormalizationEnabled }
70
+ .set { GeneralStorage.shared.isLoudnessNormalizationEnabled = $0 }
71
+
72
+ Property("autoplayOnStartEnabled")
73
+ .get { GeneralStorage.shared.isAutoplayOnStartEnabled }
74
+ .set { GeneralStorage.shared.isAutoplayOnStartEnabled = $0 }
75
+
76
+ // MARK: - Getters
77
+
78
+ AsyncFunction("getPosition") { () -> Double in
79
+ return OrpheusPlayerManager.shared.getPosition()
80
+ }
81
+
82
+ AsyncFunction("getDuration") { () -> Double in
83
+ return OrpheusPlayerManager.shared.getDuration()
84
+ }
85
+
86
+ AsyncFunction("getBuffered") { () -> Double in
87
+ return OrpheusPlayerManager.shared.getBufferedPosition()
88
+ }
89
+
90
+ AsyncFunction("getIsPlaying") { () -> Bool in
91
+ return OrpheusPlayerManager.shared.isPlaying()
92
+ }
93
+
94
+ AsyncFunction("getCurrentIndex") { () -> Int in
95
+ return OrpheusPlayerManager.shared.getCurrentIndex()
96
+ }
97
+
98
+ AsyncFunction("getCurrentTrack") { () -> Track? in
99
+ return OrpheusPlayerManager.shared.getCurrentTrack()
100
+ }
101
+
102
+ AsyncFunction("getQueue") { () -> [Track] in
103
+ return OrpheusPlayerManager.shared.getQueue()
104
+ }
105
+
106
+ AsyncFunction("getIndexTrack") { (index: Int) -> Track? in
107
+ return OrpheusPlayerManager.shared.getTrack(at: index)
108
+ }
109
+
110
+ AsyncFunction("getPlaybackSpeed") { () -> Double in
111
+ return Double(OrpheusPlayerManager.shared.getPlaybackSpeed())
112
+ }
113
+
114
+ AsyncFunction("getRepeatMode") { () -> Int in
115
+ return OrpheusPlayerManager.shared.repeatMode.rawValue
116
+ }
117
+
118
+ AsyncFunction("getShuffleMode") { () -> Bool in
119
+ return OrpheusPlayerManager.shared.shuffleMode
120
+ }
121
+
122
+ // MARK: - Controls
123
+
124
+ AsyncFunction("play") {
125
+ OrpheusPlayerManager.shared.play()
126
+ }
127
+
128
+ AsyncFunction("pause") {
129
+ OrpheusPlayerManager.shared.pause()
130
+ }
131
+
132
+ AsyncFunction("skipToNext") {
133
+ OrpheusPlayerManager.shared.playNext()
134
+ }
135
+
136
+ AsyncFunction("skipToPrevious") {
137
+ OrpheusPlayerManager.shared.skipToPrevious()
138
+ }
139
+
140
+ AsyncFunction("seekTo") { (seconds: Double) in
141
+ OrpheusPlayerManager.shared.seek(to: seconds)
142
+ }
143
+
144
+ AsyncFunction("skipTo") { (index: Int) in
145
+ OrpheusPlayerManager.shared.skipTo(index: index)
146
+ }
147
+
148
+ AsyncFunction("addToEnd") { (tracks: [Track], startFromId: String?, clearQueue: Bool) in
149
+ OrpheusPlayerManager.shared.addToEnd(tracks: tracks, startFromId: startFromId, clearQueue: clearQueue)
150
+ }
151
+
152
+ AsyncFunction("playNext") { (track: Track) in
153
+ OrpheusPlayerManager.shared.addToNext(track: track)
154
+ }
155
+
156
+ AsyncFunction("removeTrack") { (index: Int) in
157
+ OrpheusPlayerManager.shared.removeTrack(at: index)
158
+ }
159
+
160
+ AsyncFunction("clear") {
161
+ OrpheusPlayerManager.shared.clearQueue()
162
+ }
163
+
164
+ AsyncFunction("setPlaybackSpeed") { (speed: Double) in
165
+ OrpheusPlayerManager.shared.setPlaybackSpeed(Float(speed))
166
+ }
167
+
168
+ Function("setBilibiliCookie") { (cookie: String) in
169
+ BilibiliApi.shared.setCookie(cookie)
170
+ }
171
+
172
+ Function("setShuffleMode") { (enabled: Bool) in
173
+ OrpheusPlayerManager.shared.setExecuteShuffleMode(enabled)
174
+ }
175
+
176
+ Function("setRepeatMode") { (mode: Int) in
177
+ if let repeatMode = RepeatMode(rawValue: mode) {
178
+ OrpheusPlayerManager.shared.setExecuteRepeatMode(repeatMode)
179
+ }
180
+ }
181
+
182
+ Function("setSleepTimer") { (durationMs: Double) in
183
+ OrpheusPlayerManager.shared.setSleepTimer(durationMs: durationMs)
184
+ }
185
+
186
+ Function("getSleepTimerEndTime") { () -> Double? in
187
+ return OrpheusPlayerManager.shared.getSleepTimerEndTime()
188
+ }
189
+
190
+ Function("cancelSleepTimer") {
191
+ OrpheusPlayerManager.shared.cancelSleepTimer()
192
+ }
193
+
194
+ // MARK: - Downloads
195
+
196
+ Function("downloadTrack") { (track: Track) in
197
+ OrpheusDownloadManager.shared.downloadTrack(track: track)
198
+ }
199
+
200
+ Function("multiDownload") { (tracks: [Track]) in
201
+ OrpheusDownloadManager.shared.multiDownload(tracks: tracks)
202
+ }
203
+
204
+ Function("removeDownload") { (id: String) in
205
+ OrpheusDownloadManager.shared.removeDownload(id: id)
206
+ }
207
+
208
+ Function("removeAllDownloads") {
209
+ OrpheusDownloadManager.shared.removeAllDownloads()
210
+ }
211
+
212
+ Function("getDownloads") { () -> [DownloadTask] in
213
+ return OrpheusDownloadManager.shared.getDownloads()
214
+ }
215
+
216
+ Function("getDownloadStatusByIds") { (ids: [String]) -> [String: Int] in
217
+ return OrpheusDownloadManager.shared.getDownloadStatusByIds(ids: ids)
218
+ }
219
+
220
+ Function("clearUncompletedDownloadTasks") {
221
+ OrpheusDownloadManager.shared.clearUncompletedTasks()
222
+ }
223
+
224
+ Function("getUncompletedDownloadTasks") { () -> [DownloadTask] in
225
+ return OrpheusDownloadManager.shared.getUncompletedTasks()
226
+ }
227
+ }
228
+ }
@@ -0,0 +1,98 @@
1
+ import Foundation
2
+
3
+ class GeneralStorage {
4
+ static let shared = GeneralStorage()
5
+
6
+ private let defaults = UserDefaults.standard
7
+
8
+ private let KEY_SAVED_QUEUE = "saved_queue_json_list"
9
+ private let KEY_SAVED_INDEX = "saved_index"
10
+ private let KEY_SAVED_POSITION = "saved_position"
11
+ private let KEY_SAVED_REPEAT_MODE = "saved_repeat_mode"
12
+ private let KEY_SAVED_SHUFFLE_MODE = "saved_shuffle_mode"
13
+
14
+ private let KEY_RESTORE_ENABLED = "restorePlaybackPositionEnabled"
15
+ private let KEY_LOUDNESS_ENABLED = "loudnessNormalizationEnabled"
16
+ private let KEY_AUTOPLAY_ENABLED = "autoplayOnStartEnabled"
17
+ private let KEY_DESKTOP_LYRICS_SHOWN = "isDesktopLyricsShown" // Not really used in iOS but following pattern
18
+ private let KEY_DESKTOP_LYRICS_LOCKED = "isDesktopLyricsLocked"
19
+
20
+ // MARK: - Preferences
21
+
22
+ var isRestoreEnabled: Bool {
23
+ get { return defaults.bool(forKey: KEY_RESTORE_ENABLED) }
24
+ set { defaults.set(newValue, forKey: KEY_RESTORE_ENABLED) }
25
+ }
26
+
27
+ var isLoudnessNormalizationEnabled: Bool {
28
+ get { return defaults.bool(forKey: KEY_LOUDNESS_ENABLED) }
29
+ set { defaults.set(newValue, forKey: KEY_LOUDNESS_ENABLED) }
30
+ }
31
+
32
+ var isAutoplayOnStartEnabled: Bool {
33
+ get { return defaults.bool(forKey: KEY_AUTOPLAY_ENABLED) }
34
+ set { defaults.set(newValue, forKey: KEY_AUTOPLAY_ENABLED) }
35
+ }
36
+
37
+ // MARK: - Playback State
38
+
39
+ func saveQueue(_ queue: [Track]) {
40
+ do {
41
+ let jsonList = try queue.compactMap { track -> String? in
42
+ let dict = track.dictionaryRepresentation
43
+ let data = try JSONSerialization.data(withJSONObject: dict, options: [])
44
+ return String(data: data, encoding: .utf8)
45
+ }
46
+ defaults.set(jsonList, forKey: KEY_SAVED_QUEUE)
47
+ } catch {
48
+
49
+ }
50
+ }
51
+
52
+ func getSavedQueue() -> [Track] {
53
+ guard let jsonList = defaults.stringArray(forKey: KEY_SAVED_QUEUE) else { return [] }
54
+
55
+ var restoredQueue: [Track] = []
56
+ for jsonStr in jsonList {
57
+ if let data = jsonStr.data(using: .utf8),
58
+ let dict = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
59
+ let track = Track(dictionary: dict) {
60
+ restoredQueue.append(track)
61
+ }
62
+ }
63
+ return restoredQueue
64
+ }
65
+
66
+ func savePosition(index: Int, positionSec: Double) {
67
+ defaults.set(index, forKey: KEY_SAVED_INDEX)
68
+
69
+ if !positionSec.isNaN && !positionSec.isInfinite {
70
+ let positionMs = Int64(positionSec * 1000)
71
+ defaults.set(positionMs, forKey: KEY_SAVED_POSITION)
72
+ }
73
+ }
74
+
75
+ func getSavedIndex() -> Int {
76
+ return defaults.integer(forKey: KEY_SAVED_INDEX)
77
+ }
78
+
79
+ func getSavedPosition() -> Double {
80
+ return defaults.double(forKey: KEY_SAVED_POSITION) / 1000.0
81
+ }
82
+
83
+ func saveRepeatMode(_ mode: Int) {
84
+ defaults.set(mode, forKey: KEY_SAVED_REPEAT_MODE)
85
+ }
86
+
87
+ func getSavedRepeatMode() -> Int {
88
+ return defaults.integer(forKey: KEY_SAVED_REPEAT_MODE)
89
+ }
90
+
91
+ func saveShuffleMode(_ enabled: Bool) {
92
+ defaults.set(enabled, forKey: KEY_SAVED_SHUFFLE_MODE)
93
+ }
94
+
95
+ func getSavedShuffleMode() -> Bool {
96
+ return defaults.bool(forKey: KEY_SAVED_SHUFFLE_MODE)
97
+ }
98
+ }