@andycui/react-native-get-music-files 3.0.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,420 @@
1
+ #import "TurboSongs.h"
2
+ #import <MediaPlayer/MediaPlayer.h>
3
+
4
+
5
+ @implementation TurboSongs
6
+ RCT_EXPORT_MODULE()
7
+
8
+ // Example method
9
+ // See // https://reactnative.dev/docs/native-modules-ios
10
+ RCT_EXPORT_METHOD(getAll:(NSDictionary *)options
11
+ resolve:(RCTPromiseResolveBlock)resolve
12
+ reject:(RCTPromiseRejectBlock)reject)
13
+ {
14
+ if([MPMediaLibrary authorizationStatus] != MPMediaLibraryAuthorizationStatusAuthorized){
15
+ reject(@"Permission denied",@"Permission denied",0);
16
+ return;
17
+ }
18
+
19
+ NSInteger limit = [options objectForKey:@"limit"] ? [options[@"limit"] integerValue] : 20;
20
+ NSInteger offset = [options objectForKey:@"offset"] ? [options[@"offset"] integerValue] : 0;
21
+ NSInteger coverQty = [options objectForKey:@"coverQuality"] ? [options[@"coverQuality"] integerValue] : 100;
22
+ NSInteger minSongDuration = [options objectForKey:@"minSongDuration"] ? [options[@"minSongDuration"] integerValue] / 1000 : 100;
23
+
24
+ BOOL needCover = [options objectForKey:@"coverQuality"] != nil || [options[@"coverQuality"] integerValue] == 0;
25
+
26
+ id sortOrderValue = [options objectForKey:@"sortOrder"];
27
+
28
+ NSString *sortOrder;
29
+ if ([sortOrderValue isKindOfClass:[NSString class]]) {
30
+ sortOrder = sortOrderValue;
31
+ } else {
32
+ sortOrder = @"ASC";
33
+ }
34
+
35
+ id sortByValue = [options objectForKey:@"sortBy"];
36
+
37
+ NSString *sortBy;
38
+ if ([sortByValue isKindOfClass:[NSString class]]) {
39
+ sortBy = sortByValue;
40
+ } else {
41
+ sortBy = @"TITLE";
42
+ }
43
+
44
+ NSMutableArray *mutableSongsToSerialize = [NSMutableArray array];
45
+
46
+ MPMediaQuery *mediaQuery = [MPMediaQuery songsQuery]; // run a query on song media type
47
+ [mediaQuery addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:@(NO)
48
+ forProperty:MPMediaItemPropertyIsCloudItem]]; // ensure what we retrieve is on device
49
+
50
+ NSArray *allMediaItems = [mediaQuery items];
51
+
52
+ // Define the range for the limited subset
53
+ NSRange range = NSMakeRange(offset, MIN(limit, allMediaItems.count - offset));
54
+
55
+ // Get the subset of media items within the specified range
56
+ NSArray<MPMediaItem *> *limitedMediaItems = [allMediaItems subarrayWithRange:range];
57
+
58
+ // Sort items
59
+ NSArray<MPMediaItem *> *sortedMediaItems = [self sortMediaItems:limitedMediaItems byKey: sortBy sortOrder: sortOrder];
60
+
61
+ for (MPMediaItem *song in sortedMediaItems) {
62
+ NSDictionary *songDictionary = [NSMutableDictionary dictionary];
63
+
64
+ NSString *durationStr = [song valueForProperty: MPMediaItemPropertyPlaybackDuration];
65
+ NSInteger durationInt = [durationStr integerValue];
66
+
67
+ NSURL *assetURL = [song valueForProperty:MPMediaItemPropertyAssetURL];
68
+ AVAsset *asset = [AVAsset assetWithURL:assetURL];
69
+
70
+ if ([asset hasProtectedContent] == NO and durationInt >= minSongDuration) {
71
+
72
+ NSString *title = [song valueForProperty: MPMediaItemPropertyTitle];
73
+ NSString *albumTitle = [song valueForProperty: MPMediaItemPropertyAlbumTitle];
74
+ NSString *albumArtist = [song valueForProperty: MPMediaItemPropertyAlbumArtist];
75
+ NSString *genre = [song valueForProperty: MPMediaItemPropertyGenre]; // filterable
76
+
77
+ [songDictionary setValue:[NSString stringWithString:assetURL.absoluteString] forKey:@"url"];
78
+ [songDictionary setValue:[NSString stringWithString:title] forKey:@"title"];
79
+ [songDictionary setValue:[NSString stringWithString:albumTitle] forKey:@"album"];
80
+ [songDictionary setValue:[NSString stringWithString:albumArtist] forKey:@"artist"];
81
+ [songDictionary setValue:[NSNumber numberWithInt:durationInt * 1000] forKey:@"duration"];
82
+ [songDictionary setValue:[NSString stringWithString:genre] forKey:@"genre"];
83
+
84
+ if (needCover) {
85
+ MPMediaItemArtwork *artwork = [song valueForProperty: MPMediaItemPropertyArtwork];
86
+ if (artwork != nil) {
87
+ UIImage *image = [artwork imageWithSize:CGSizeMake(coverQty, coverQty)];
88
+ // http://www.12qw.ch/2014/12/tooltip-decoding-base64-images-with-chrome-data-url/
89
+ // http://stackoverflow.com/a/510444/185771
90
+ NSString *base64 = [NSString stringWithFormat:@"%@%@", @"data:image/jpeg;base64,", [self imageToNSString:image]];
91
+ [songDictionary setValue:base64 forKey:@"cover"];
92
+ } else {
93
+ [songDictionary setValue:@"" forKey:@"cover"];
94
+ }
95
+ } else {
96
+ [songDictionary setValue:@"" forKey:@"cover"];
97
+ }
98
+
99
+ [mutableSongsToSerialize addObject:songDictionary];
100
+ }
101
+ }
102
+
103
+ resolve(mutableSongsToSerialize);
104
+ }
105
+
106
+ RCT_EXPORT_METHOD(getAlbums:(NSDictionary *)options
107
+ resolve:(RCTPromiseResolveBlock)resolve
108
+ reject:(RCTPromiseRejectBlock)reject)
109
+ {
110
+
111
+ if([MPMediaLibrary authorizationStatus] != MPMediaLibraryAuthorizationStatusAuthorized){
112
+ reject(@"Permission denied",@"Permission denied",0);
113
+ return;
114
+ }
115
+
116
+ NSInteger limit = [options objectForKey:@"limit"] ? [options[@"limit"] integerValue] : 20;
117
+ NSInteger offset = [options objectForKey:@"offset"] ? [options[@"offset"] integerValue] : 0;
118
+ NSInteger coverQty = [options objectForKey:@"coverQuality"] ? [options[@"coverQuality"] integerValue] : 100;
119
+ NSString *artist = options[@"artist"];
120
+
121
+ BOOL needCover = [options objectForKey:@"coverQuality"] != nil || [options[@"coverQuality"] integerValue] == 0;
122
+
123
+ id sortOrderValue = [options objectForKey:@"sortOrder"];
124
+
125
+ NSString *sortOrder;
126
+ if ([sortOrderValue isKindOfClass:[NSString class]]) {
127
+ sortOrder = sortOrderValue;
128
+ } else {
129
+ sortOrder = @"ASC";
130
+ }
131
+
132
+ id sortByValue = [options objectForKey:@"sortBy"];
133
+
134
+ NSString *sortBy;
135
+ if ([sortByValue isKindOfClass:[NSString class]]) {
136
+ sortBy = sortByValue;
137
+ } else {
138
+ sortBy = @"TITLE";
139
+ }
140
+
141
+ if(artist.length == 0){
142
+ reject(@"Artist name must not be empty",@"Artist name must not be empty",0);
143
+ return;
144
+ }
145
+
146
+ NSMutableArray *mutableSongsToSerialize = [NSMutableArray array];
147
+
148
+ MPMediaQuery *mediaQuery = [MPMediaQuery albumsQuery]; // run a query on song media type
149
+ [mediaQuery addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:@(NO)
150
+ forProperty:MPMediaItemPropertyIsCloudItem]]; // ensure what we retrieve is on device
151
+ // this is returning all songs no matter what
152
+ [mediaQuery addFilterPredicate:[
153
+ MPMediaPropertyPredicate
154
+ predicateWithValue:artist
155
+ forProperty:MPMediaItemPropertyArtist
156
+ comparisonType: MPMediaPredicateComparisonContains
157
+ ]
158
+ ];
159
+
160
+ NSArray *allMediaItems = [mediaQuery items];
161
+
162
+ // Define the range for the limited subset
163
+ NSRange range = NSMakeRange(offset, MIN(limit, allMediaItems.count - offset));
164
+
165
+ // Get the subset of media items within the specified range
166
+ NSArray<MPMediaItem *> *limitedMediaItems = [allMediaItems subarrayWithRange:range];
167
+
168
+ // Sort items
169
+ NSArray<MPMediaItem *> *sortedMediaItems = [self sortMediaItems:limitedMediaItems byKey: sortBy sortOrder: sortOrder];
170
+
171
+ for (MPMediaItem *album in sortedMediaItems) {
172
+ NSDictionary *songDictionary = [NSMutableDictionary dictionary];
173
+
174
+ NSURL *assetURL = [album valueForProperty:MPMediaItemPropertyAssetURL];
175
+ AVAsset *asset = [AVAsset assetWithURL:assetURL];
176
+
177
+ if ([asset hasProtectedContent] == NO) {
178
+
179
+ NSString *albumTitle = [album valueForProperty: MPMediaItemPropertyAlbumTitle]; // filterable
180
+ NSString *albumArtist = [album valueForProperty: MPMediaItemPropertyAlbumArtist]; //
181
+ NSString *numberOfSongs = [album valueForProperty: MPMediaItemPropertyAlbumTrackCount]; //
182
+
183
+ [songDictionary setValue:[NSString stringWithString:assetURL.absoluteString] forKey:@"url"];
184
+ [songDictionary setValue:[NSString stringWithString:albumTitle] forKey:@"album"];
185
+ [songDictionary setValue:[NSString stringWithString:albumArtist] forKey:@"artist"];
186
+ [songDictionary setValue:[NSString stringWithString:numberOfSongs] forKey:@"numberOfSongs"];
187
+
188
+ if (needCover) {
189
+ MPMediaItemArtwork *artwork = [album valueForProperty: MPMediaItemPropertyArtwork];
190
+ if (artwork != nil) {
191
+ UIImage *image = [artwork imageWithSize:CGSizeMake(coverQty, coverQty)];
192
+ // http://www.12qw.ch/2014/12/tooltip-decoding-base64-images-with-chrome-data-url/
193
+ // http://stackoverflow.com/a/510444/185771
194
+ NSString *base64 = [NSString stringWithFormat:@"%@%@", @"data:image/jpeg;base64,", [self imageToNSString:image]];
195
+ [songDictionary setValue:base64 forKey:@"cover"];
196
+ } else {
197
+ [songDictionary setValue:@"" forKey:@"cover"];
198
+ }
199
+ } else {
200
+ [songDictionary setValue:@"" forKey:@"cover"];
201
+ }
202
+
203
+ [mutableSongsToSerialize addObject:songDictionary];
204
+ }
205
+ }
206
+
207
+ resolve(mutableSongsToSerialize);
208
+ }
209
+
210
+ RCT_EXPORT_METHOD(search:(NSDictionary *)options
211
+ resolve:(RCTPromiseResolveBlock)resolve
212
+ reject:(RCTPromiseRejectBlock)reject)
213
+ {
214
+ if([MPMediaLibrary authorizationStatus] != MPMediaLibraryAuthorizationStatusAuthorized){
215
+ reject(@"Permission denied",@"Permission denied",0);
216
+ return;
217
+ }
218
+
219
+ NSInteger limit = [options objectForKey:@"limit"] ? [options[@"limit"] integerValue] : 20;
220
+ NSInteger offset = [options objectForKey:@"offset"] ? [options[@"offset"] integerValue] : 0;
221
+ NSInteger coverQty = [options objectForKey:@"coverQuality"] ? [options[@"coverQuality"] integerValue] : 100;
222
+ NSString *searchBy = options[@"searchBy"];
223
+
224
+ BOOL needCover = [options objectForKey:@"coverQuality"] != nil || [options[@"coverQuality"] integerValue] == 0;
225
+
226
+ id sortOrderValue = [options objectForKey:@"sortOrder"];
227
+
228
+ NSString *sortOrder;
229
+ if ([sortOrderValue isKindOfClass:[NSString class]]) {
230
+ sortOrder = sortOrderValue;
231
+ } else {
232
+ sortOrder = @"ASC";
233
+ }
234
+
235
+ id sortByValue = [options objectForKey:@"sortBy"];
236
+
237
+ NSString *sortBy;
238
+ if ([sortByValue isKindOfClass:[NSString class]]) {
239
+ sortBy = sortByValue;
240
+ } else {
241
+ sortBy = @"TITLE";
242
+ }
243
+
244
+ if(searchBy.length == 0){
245
+ reject(@"Search param must not be empty",@"Search param must not be empty",0);
246
+ return;
247
+ }
248
+
249
+ NSMutableArray *mutableSongsToSerialize = [NSMutableArray array];
250
+
251
+ MPMediaQuery *mediaQuery = [MPMediaQuery songsQuery]; // run a query on song media type
252
+ [mediaQuery addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:@(NO)
253
+ forProperty:MPMediaItemPropertyIsCloudItem]]; // ensure what we retrieve is on device
254
+
255
+ NSPredicate *filters = [NSPredicate predicateWithFormat:@"title contains[cd] %@ OR albumTitle contains[cd] %@ OR artist contains[cd] %@", searchBy, searchBy, searchBy];
256
+
257
+ NSArray *allMediaItems = [[mediaQuery items] filteredArrayUsingPredicate:filters];
258
+
259
+
260
+ // Define the range for the limited subset
261
+ NSRange range = NSMakeRange(offset, MIN(limit, allMediaItems.count - offset));
262
+
263
+ // Get the subset of media items within the specified range
264
+ NSArray<MPMediaItem *> *limitedMediaItems = [allMediaItems subarrayWithRange:range];
265
+
266
+ // Sort items
267
+ NSArray<MPMediaItem *> *sortedMediaItems = [self sortMediaItems:limitedMediaItems byKey: sortBy sortOrder: sortOrder];
268
+
269
+ for (MPMediaItem *song in sortedMediaItems) {
270
+ NSDictionary *songDictionary = [NSMutableDictionary dictionary];
271
+
272
+ NSURL *assetURL = [song valueForProperty:MPMediaItemPropertyAssetURL];
273
+ AVAsset *asset = [AVAsset assetWithURL:assetURL];
274
+
275
+ if ([asset hasProtectedContent] == NO) {
276
+
277
+ NSString *durationStr = [song valueForProperty: MPMediaItemPropertyPlaybackDuration];
278
+ NSInteger durationInt = [durationStr integerValue];
279
+
280
+ NSString *title = [song valueForProperty: MPMediaItemPropertyTitle];
281
+ NSString *albumTitle = [song valueForProperty: MPMediaItemPropertyAlbumTitle];
282
+ NSString *albumArtist = [song valueForProperty: MPMediaItemPropertyAlbumArtist];
283
+ NSString *genre = [song valueForProperty: MPMediaItemPropertyGenre]; // filterable
284
+
285
+ [songDictionary setValue:[NSString stringWithString:assetURL.absoluteString] forKey:@"url"];
286
+ [songDictionary setValue:[NSString stringWithString:title] forKey:@"title"];
287
+ [songDictionary setValue:[NSString stringWithString:albumTitle] forKey:@"album"];
288
+ [songDictionary setValue:[NSString stringWithString:albumArtist] forKey:@"artist"];
289
+ [songDictionary setValue:[NSNumber numberWithInt:durationInt * 1000] forKey:@"duration"];
290
+ [songDictionary setValue:[NSString stringWithString:genre] forKey:@"genre"];
291
+
292
+ if (needCover) {
293
+ MPMediaItemArtwork *artwork = [song valueForProperty: MPMediaItemPropertyArtwork];
294
+ if (artwork != nil) {
295
+ UIImage *image = [artwork imageWithSize:CGSizeMake(coverQty, coverQty)];
296
+ // http://www.12qw.ch/2014/12/tooltip-decoding-base64-images-with-chrome-data-url/
297
+ // http://stackoverflow.com/a/510444/185771
298
+ NSString *base64 = [NSString stringWithFormat:@"%@%@", @"data:image/jpeg;base64,", [self imageToNSString:image]];
299
+ [songDictionary setValue:base64 forKey:@"cover"];
300
+ } else {
301
+ [songDictionary setValue:@"" forKey:@"cover"];
302
+ }
303
+ } else {
304
+ [songDictionary setValue:@"" forKey:@"cover"];
305
+ }
306
+
307
+ [mutableSongsToSerialize addObject:songDictionary];
308
+ }
309
+ }
310
+
311
+ resolve(mutableSongsToSerialize);
312
+ }
313
+
314
+ // http://stackoverflow.com/questions/22243854/encode-image-to-base64-get-a-invalid-base64-string-ios-using-base64encodedstri
315
+ - (NSString *)imageToNSString:(UIImage *)image
316
+ {
317
+ NSData *data = UIImagePNGRepresentation(image);
318
+
319
+ return [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
320
+ }
321
+
322
+ - (NSArray<MPMediaItem *> *)sortMediaItems:(NSArray<MPMediaItem *> *)mediaItems byKey:(NSString *)sortKey sortOrder:(NSString *)sortOrder {
323
+ NSArray<MPMediaItem *> *sortedMediaItems;
324
+
325
+ if ([sortKey isEqualToString:@"DURATION"]) {
326
+ sortedMediaItems = [mediaItems sortedArrayUsingComparator:^NSComparisonResult(MPMediaItem *item1, MPMediaItem *item2) {
327
+ NSNumber *duration1 = [item1 valueForProperty:MPMediaItemPropertyPlaybackDuration];
328
+ NSNumber *duration2 = [item2 valueForProperty:MPMediaItemPropertyPlaybackDuration];
329
+ NSComparisonResult result = [duration1 compare:duration2];
330
+
331
+ if ([sortOrder isEqualToString:@"DESC"]) {
332
+ return (result == NSOrderedAscending) ? NSOrderedDescending :
333
+ (result == NSOrderedDescending) ? NSOrderedAscending : NSOrderedSame;
334
+ }
335
+
336
+ return result;
337
+ }];
338
+ } else if ([sortKey isEqualToString:@"TITLE"]) {
339
+ sortedMediaItems = [mediaItems sortedArrayUsingComparator:^NSComparisonResult(MPMediaItem *item1, MPMediaItem *item2) {
340
+ NSString *title1 = [item1 valueForProperty:MPMediaItemPropertyTitle];
341
+ NSString *title2 = [item2 valueForProperty:MPMediaItemPropertyTitle];
342
+ NSComparisonResult result = [title1 compare:title2];
343
+
344
+ if ([sortOrder isEqualToString:@"DESC"]) {
345
+ return (result == NSOrderedAscending) ? NSOrderedDescending :
346
+ (result == NSOrderedDescending) ? NSOrderedAscending : NSOrderedSame;
347
+ }
348
+
349
+ return result;
350
+ }];
351
+ } else if ([sortKey isEqualToString:@"ARTIST"]) {
352
+ sortedMediaItems = [mediaItems sortedArrayUsingComparator:^NSComparisonResult(MPMediaItem *item1, MPMediaItem *item2) {
353
+ NSString *artist1 = [item1 valueForProperty:MPMediaItemPropertyArtist];
354
+ NSString *artist2 = [item2 valueForProperty:MPMediaItemPropertyArtist];
355
+ NSComparisonResult result = [artist1 compare:artist2];
356
+
357
+ if ([sortOrder isEqualToString:@"DESC"]) {
358
+ return (result == NSOrderedAscending) ? NSOrderedDescending :
359
+ (result == NSOrderedDescending) ? NSOrderedAscending : NSOrderedSame;
360
+ }
361
+
362
+ return result;
363
+ }];
364
+ } else if ([sortKey isEqualToString:@"ALBUM"]) {
365
+ sortedMediaItems = [mediaItems sortedArrayUsingComparator:^NSComparisonResult(MPMediaItem *item1, MPMediaItem *item2) {
366
+ NSString *album1 = [item1 valueForProperty:MPMediaItemPropertyAlbumTitle];
367
+ NSString *album2 = [item2 valueForProperty:MPMediaItemPropertyAlbumTitle];
368
+ NSComparisonResult result = [album1 compare:album2];
369
+
370
+ if ([sortOrder isEqualToString:@"DESC"]) {
371
+ return (result == NSOrderedAscending) ? NSOrderedDescending :
372
+ (result == NSOrderedDescending) ? NSOrderedAscending : NSOrderedSame;
373
+ }
374
+
375
+ return result;
376
+ }];
377
+ } else if ([sortKey isEqualToString:@"GENDER"]) {
378
+ sortedMediaItems = [mediaItems sortedArrayUsingComparator:^NSComparisonResult(MPMediaItem *item1, MPMediaItem *item2) {
379
+ NSString *gender1 = [item1 valueForProperty:MPMediaItemPropertyGenre];
380
+ NSString *gender2 = [item2 valueForProperty:MPMediaItemPropertyGenre];
381
+ NSComparisonResult result = [gender1 compare:gender2];
382
+
383
+ if ([sortOrder isEqualToString:@"DESC"]) {
384
+ return (result == NSOrderedAscending) ? NSOrderedDescending :
385
+ (result == NSOrderedDescending) ? NSOrderedAscending : NSOrderedSame;
386
+ }
387
+
388
+ return result;
389
+ }];
390
+ } else if ([sortKey isEqualToString:@"DATE_ADDED"]) {
391
+ sortedMediaItems = [mediaItems sortedArrayUsingComparator:^NSComparisonResult(MPMediaItem *item1, MPMediaItem *item2) {
392
+ NSString *dateAdded1 = [item1 valueForProperty:MPMediaItemPropertyDateAdded];
393
+ NSString *dateAdded2 = [item2 valueForProperty:MPMediaItemPropertyDateAdded];
394
+ NSComparisonResult result = [dateAdded1 compare:dateAdded2];
395
+
396
+ if ([sortOrder isEqualToString:@"DESC"]) {
397
+ return (result == NSOrderedAscending) ? NSOrderedDescending :
398
+ (result == NSOrderedDescending) ? NSOrderedAscending : NSOrderedSame;
399
+ }
400
+
401
+ return result;
402
+ }];
403
+ } else {
404
+ // Default sorting (by title)
405
+ sortedMediaItems = mediaItems;
406
+ }
407
+
408
+ return sortedMediaItems;
409
+ }
410
+
411
+ // Don't compile this code when we build for the old architecture.
412
+ #ifdef RCT_NEW_ARCH_ENABLED
413
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
414
+ (const facebook::react::ObjCTurboModule::InitParams &)params
415
+ {
416
+ return std::make_shared<facebook::react::NativeTurboSongsSpecJSI>(params);
417
+ }
418
+ #endif
419
+
420
+ @end
package/package.json ADDED
@@ -0,0 +1,171 @@
1
+ {
2
+ "name": "@andycui/react-native-get-music-files",
3
+ "version": "3.0.1",
4
+ "description": "React Native package to get music files from local and sd for iOS and Android",
5
+ "main": "lib/commonjs/index",
6
+ "module": "lib/module/index",
7
+ "types": "lib/typescript/src/index.d.ts",
8
+ "react-native": "src/index",
9
+ "source": "src/index",
10
+ "files": [
11
+ "src",
12
+ "lib",
13
+ "android",
14
+ "ios",
15
+ "cpp",
16
+ "*.podspec",
17
+ "!ios/build",
18
+ "!android/build",
19
+ "!android/gradle",
20
+ "!android/gradlew",
21
+ "!android/gradlew.bat",
22
+ "!android/local.properties",
23
+ "!**/__tests__",
24
+ "!**/__fixtures__",
25
+ "!**/__mocks__",
26
+ "!**/.*"
27
+ ],
28
+ "scripts": {
29
+ "example": "yarn workspace react-native-turbo-songs-example",
30
+ "test": "jest",
31
+ "typecheck": "tsc --noEmit",
32
+ "lint": "eslint \"**/*.{js,ts,tsx}\"",
33
+ "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
34
+ "release": "release-it"
35
+ },
36
+ "keywords": [
37
+ "react-native",
38
+ "music",
39
+ "files",
40
+ "metadata",
41
+ "ios",
42
+ "android",
43
+ "react",
44
+ "native"
45
+ ],
46
+ "repository": "https://github.com/andy380743909/react-native-get-music-files",
47
+ "author": "Andy Cui <andy380743909@gmail.com>",
48
+ "license": "MIT",
49
+ "bugs": {
50
+ "url": "https://github.com/andy380743909/react-native-get-music-files/issues"
51
+ },
52
+ "homepage": "https://github.com/andy380743909/react-native-get-music-files#readme",
53
+ "publishConfig": {
54
+ "registry": "https://registry.npmjs.org/"
55
+ },
56
+ "devDependencies": {
57
+ "@commitlint/config-conventional": "^17.0.2",
58
+ "@evilmartians/lefthook": "^1.5.0",
59
+ "@react-native/eslint-config": "^0.72.2",
60
+ "@release-it/conventional-changelog": "^5.0.0",
61
+ "@types/jest": "^28.1.2",
62
+ "@types/react": "~17.0.21",
63
+ "@types/react-native": "0.70.0",
64
+ "commitlint": "^17.0.2",
65
+ "del-cli": "^5.0.0",
66
+ "eslint": "^8.4.1",
67
+ "eslint-config-prettier": "^8.5.0",
68
+ "eslint-plugin-prettier": "^4.0.0",
69
+ "jest": "^28.1.1",
70
+ "pod-install": "^0.1.0",
71
+ "prettier": "^2.0.5",
72
+ "react": "18.2.0",
73
+ "react-native": "0.72.5",
74
+ "react-native-builder-bob": "^0.40.17",
75
+ "release-it": "^15.0.0",
76
+ "turbo": "^1.10.7",
77
+ "typescript": "^5.0.2"
78
+ },
79
+ "resolutions": {
80
+ "@types/react": "17.0.21"
81
+ },
82
+ "peerDependencies": {
83
+ "react": "*",
84
+ "react-native": "*"
85
+ },
86
+ "workspaces": [
87
+ "example"
88
+ ],
89
+ "packageManager": "yarn@3.6.1",
90
+ "engines": {
91
+ "node": ">= 18.0.0"
92
+ },
93
+ "jest": {
94
+ "preset": "react-native",
95
+ "modulePathIgnorePatterns": [
96
+ "<rootDir>/example/node_modules",
97
+ "<rootDir>/lib/"
98
+ ]
99
+ },
100
+ "commitlint": {
101
+ "extends": [
102
+ "@commitlint/config-conventional"
103
+ ]
104
+ },
105
+ "release-it": {
106
+ "git": {
107
+ "commitMessage": "chore: release ${version}",
108
+ "tagName": "v${version}"
109
+ },
110
+ "npm": {
111
+ "publish": true
112
+ },
113
+ "github": {
114
+ "release": true
115
+ },
116
+ "plugins": {
117
+ "@release-it/conventional-changelog": {
118
+ "preset": "angular"
119
+ }
120
+ }
121
+ },
122
+ "eslintConfig": {
123
+ "root": true,
124
+ "extends": [
125
+ "@react-native",
126
+ "prettier"
127
+ ],
128
+ "rules": {
129
+ "prettier/prettier": [
130
+ "error",
131
+ {
132
+ "quoteProps": "consistent",
133
+ "singleQuote": true,
134
+ "tabWidth": 2,
135
+ "trailingComma": "es5",
136
+ "useTabs": false
137
+ }
138
+ ]
139
+ }
140
+ },
141
+ "eslintIgnore": [
142
+ "node_modules/",
143
+ "lib/"
144
+ ],
145
+ "prettier": {
146
+ "quoteProps": "consistent",
147
+ "singleQuote": true,
148
+ "tabWidth": 2,
149
+ "trailingComma": "es5",
150
+ "useTabs": false
151
+ },
152
+ "react-native-builder-bob": {
153
+ "source": "src",
154
+ "output": "lib",
155
+ "targets": [
156
+ "commonjs",
157
+ "module",
158
+ [
159
+ "typescript",
160
+ {
161
+ "project": "tsconfig.build.json"
162
+ }
163
+ ]
164
+ ]
165
+ },
166
+ "codegenConfig": {
167
+ "name": "RNTurboSongsSpec",
168
+ "type": "modules",
169
+ "jsSrcsDir": "src"
170
+ }
171
+ }
@@ -0,0 +1,41 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+ folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
5
+
6
+ Pod::Spec.new do |s|
7
+ s.name = "react-native-turbo-songs"
8
+ s.version = package["version"]
9
+ s.summary = package["description"]
10
+ s.homepage = package["homepage"]
11
+ s.license = package["license"]
12
+ s.authors = package["author"]
13
+
14
+ s.platforms = { :ios => "11.0" }
15
+ s.source = { :git => "https://.git", :tag => "#{s.version}" }
16
+
17
+ s.source_files = "ios/**/*.{h,m,mm}"
18
+
19
+ # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
20
+ # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
21
+ if respond_to?(:install_modules_dependencies, true)
22
+ install_modules_dependencies(s)
23
+ else
24
+ s.dependency "React-Core"
25
+
26
+ # Don't install the dependencies when we run `pod install` in the old architecture.
27
+ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
28
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
29
+ s.pod_target_xcconfig = {
30
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
31
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
32
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
33
+ }
34
+ s.dependency "React-Codegen"
35
+ s.dependency "RCT-Folly"
36
+ s.dependency "RCTRequired"
37
+ s.dependency "RCTTypeSafety"
38
+ s.dependency "ReactCommon/turbomodule/core"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,60 @@
1
+ import type { TurboModule } from 'react-native';
2
+ import { TurboModuleRegistry } from 'react-native';
3
+
4
+ export interface Song {
5
+ url: string;
6
+ title: string;
7
+ album: string;
8
+ artist: string;
9
+ duration: number;
10
+ genre: string;
11
+ cover: string;
12
+ }
13
+
14
+ enum SortSongOrder {
15
+ ASC = 'ASC',
16
+ DESC = 'DESC',
17
+ }
18
+
19
+ enum SortSongFields {
20
+ TITLE = 'TITLE',
21
+ DURATION = 'DURATION',
22
+ ARTIST = 'ARTIST',
23
+ GENRE = 'GENRE',
24
+ ALBUM = 'ALBUM',
25
+ DATE_ADDED = 'DATE_ADDED',
26
+ }
27
+
28
+ export interface SongOptions {
29
+ limit?: number;
30
+ offset?: number;
31
+ coverQuality?: number;
32
+ minSongDuration?: number;
33
+ searchBy?: string;
34
+ sortOrder?: SortSongOrder;
35
+ sortBy?: SortSongFields;
36
+ }
37
+
38
+ export interface Album {
39
+ url: string;
40
+ album: string;
41
+ artist: string;
42
+ numberOfSongs: string;
43
+ cover: string;
44
+ }
45
+ export interface AlbumOptions {
46
+ limit?: number;
47
+ offset?: number;
48
+ coverQuality?: number;
49
+ artist: string;
50
+ sortOrder?: SortSongOrder;
51
+ sortBy?: SortSongOrder;
52
+ }
53
+
54
+ export interface Spec extends TurboModule {
55
+ getAll(options?: SongOptions): Promise<Song[] | string>;
56
+ getAlbums(options?: AlbumOptions): Promise<Album[] | string>;
57
+ searchSongs(options?: SongOptions): Promise<Song[] | string>;
58
+ }
59
+
60
+ export default TurboModuleRegistry.getEnforcing<Spec>('TurboSongs');