Плеер который проигрывает музыку из яндекс диска
Перейти к содержимому

Плеер который проигрывает музыку из яндекс диска

  • автор:

Яндекс.Музыка

Яндекс.Музыка

Яндекс.Музыка — музыкальный плеер с поддержкой воспроизведения музыки, хранящейся на мобильном устройстве пользователя, в облачном хранилище Яндекс.Диск, а также через онлайновый сервис Яндекс.Музыка в режиме радио. Приложение полностью бесплатное, как и большинство сервисов, им предоставляемых. Так, вы можете слушать треки, хранящихся на вашем Android-смартфоне или в вашем персональном хранилище в Яндекс.Диске.

В режиме радио вы сможете выбирать жанр музыки, просматривать информацию об исполнителях, добавлять треки в плейлисты. При чем плейлисты могут содержать музыку из разных источников.

Приложение умеет распознавать музыкальные композиции. Просто поднесите смартфон к динамику телевизора, радио или к колонке и за считанные секунды узнайте что за музыка играет.

Оформив платную подписку на сервис, вы сможете слушать произвольные треки из каталога Яндекс.Музыки, сохранять музыку на свой гаджет чтобы слушать ее в офлайне. Вы также получите возможность произвольно переключать и перематывать треки во время прослушивания радио.

Во что разработчики превратили легендарный плеер AIMP

Мне понадобился легкий плеер для компьютера, который мог бы проигрывать музыку из облачного хранилища Google или Яндекс. Случайно заметил, что популярный, и даже легендарный, AIMP еще жив. Решил посмотреть, как он изменился, и был приятно удивлен.

Как живет плеер AIMP?

При первом запуске пользователя ждет пугающе пустое окно.

Начать стоит с настройки библиотеки музыки. Она делается добавлением папок с музыкой через кнопку с плюсом. Все само добавится и каталогизируется по тегам.

Интерфейс простой, легкий. Кому хочется понастальгировать по старым оранжевым кнопкам-апельсинам Аимпа, можно поменять обложку.

Из последних веяний интерфейсов появилась поддержка темной схемы. Включается автоматически или отдельной кнопкой в правом углу.

В остальном Аимп остался прежним приятным и легким (дистрибутив весит всего 11,7 Мб) плеером. Скачал и слущай!

Что нового появилось в AIMP

Прослушивание музыки из облака

Для меня наиболее яркой новостью стало не появление Темной схемы, а нативная поддержка облачных хранилищ. На моем ноутбуке размер SSD составляет всего 256 Гб. Хранить музыку мне удобнее в облачном хранилище. В Aimp подключить его можно в два клика.

  • Переходим во вкладку Мои облака.
  • Нажимаем кнопку с плюсом.

Важно, что вводить пароль не нужно. Можно получить токен для доступа. А он выдается средствами самого облака. Вот как это выглядит при подключении к Яндекс.Диску.

Нас перебрасывает на Яндекс для авторизации. После этого можете слушать музыку на облаке столь же просто, как и с локального диска.

Поддерживаются Google, Яндекс, DropBox и другие популярные сервисы.

Прослушивание подкастов

Появился в AIMP и плагин для подписки на подкасты. Находим любимый канал, ищем кнопку подписаться и копируем с нее ссылку. Вот пример.

Затем нажимаем правую клавишу мыши и копируем ссылку.

Понравилась статья? Поделитесь!

Читайте также:

  1. AIMP 5.11.2435 — один из лучших бесплатных плееров
  2. Яндекс.Музыка: бесплатная музыка на все случаи жизни
  3. Яндекс.Браузер — что это такое и почему он набирает популярность
  4. Бесплатное облачное хранилище в 2022 году: какое выбрать
  5. 3 причины установить Яндекс.Диск прямо сейчас

Пять лучших и бесплатных офлайн-плееров музыки для iPhone. Сейчас особенно актуально

Favorite

В закладки

Пять лучших и бесплатных офлайн-плееров музыки для iPhone. Сейчас особенно актуально

Вот уже несколько месяцев я всё реже запускаю Apple Music, потому что количество музыкальных новинок в этом стримингововм сервисе для России сильно поубавилось.

Если раньше можно было просто зайти на страничку с релизами и увидеть, что появилась парочка свежих альбомов от групп, которые мне нравятся, то сейчас в этом разделе лично для меня сплошная тоска. Я уже давно не видел там ничего хорошего.

То же самое касается и других онлайн-поставщиков музыки: с уходом западных лейблов свежие альбомы Nickelback, Disturbed, The Pretty Reckless и многих других просто невозможно послушать по подписке . Так что я всё чаще запускаю офлайн-плеер вместо Apple Music и слушаю заранее скачанную на свой смартфон музыку.

Как в старые добрые времена.

Далее расскажу о пяти самых удобных, бесплатных и функциональных приложениях, каждое из которых позволяет с комфортом слушать заранее загруженную музыку без всяких подписок, регистраций и смс. Приложения скачиваются из App Store, ну а где взять свежие альбомы любимых групп, я думаю вы сами знаете.

1. Flacbox. Самый навороченный бесплатный плеер

Несмотря на своё название, плеер Flacbox проигрывает практически все популярные форматы аудио, будь то wav, flac или mp3. Этим плеером я пользуюсь чаще остальных и в скором времени планирую оставить только его, благо бесплатного функционала хватает с лихвой.

В частности, Flacbox может объединить в себе как закачанную на смартфон музыку, так и треки из Apple Music: нужно лишь привязать свой аккаунт стримингового сервиса.

Также к Flacbox можно подключить любые из популярных облачных хранилищ и стримить музыку оттуда. Это особенно будет удобно владельцам большой аудио-библиотеки и айфона с малым количеством памяти. Просто заливаете всю свою медиатеку в облако и получаете свой личный стриминговый сервис.

Поддерживаются следующие облака:

▪️ Google Drive
▪️ Dropbox
▪️ OneDrive
▪️ Яндекс.Диск
▪️ MEGA
▪️ My Cloud Home
▪️ Box
▪️ SMB

В настройках плеера можно настроить порядок воспроизведения, поставить таймер сна, активировать фоновый режим или воспользоваться сортировкой треков по альбомам, исполнителям и прочим параметрам. Добавьте к этому поддержку CarPlay и AirPlay и получится практически идеальный музыкальный комбайн.

В Flacbox есть возможность оформить подписку за деньги, но только если вам необходимо пользоваться встроенным эквалайзером. Всё остальное вышеперечисленное доступно сразу после скачивания приложения совершенно бесплатно.

2. Offline Player. Аудио и видео комбайн

Это приложение даже не плеер, а мультимедийная библиотека, в которой можно искать треки по всем открытым источникам автоматически. Кроме того, есть поддержка прямой закачки своих аудиофайлов с помощью Wi-Fi Direct, приятный интерфейс и плюшки в виде таймера сна и возможности добавлять свои обложки к трекам.

Можно оплатить подписку, но её плюс заключается лишь в возможности смены «скинов» плеера, так что тратиться совершенно необязательно. В остальном этот плеер можно использовать чтобы просто включить музыку из интернета, без всяких подписок и регистраций.

3. jetAudio. Самый красивый плеер с базовыми функциями

Создатели jetAudio подобрали поразительно приятное цветовое оформление плеера, несмотря на присутствие всего двух цветов, серого и зелёного. На экране минимум кнопок, управление интуитивно понятное, поддерживаются форматы Flac, mp3, Wav, Ogg и несколько других.

Из особенностей могу отметить кучу настроек по улучшению звука, начиная от продвинутого эквалайзера, заканчивая несколькими запатентованными «улучшайзерами». Правда все это великолепие становится доступным, если оплатить подписку.

Изредка появляется реклама в бесплатной версии, но она абсолютно ненавязчивая. После оплаты подписки становятся доступны изменения цветов интерфейса, звуковые тонкие настройки и несколько совсем незначительных параметров. В целом, удобный и лаконичный плеер, который стоит попробовать.

4. VLC. Видеоплеер, который и аудио отлично играет

Зарекомендовавший себя видеоплеер для iOS отлично подходит и для использования в качестве аудиопроигрывателя. Поддержка всех популярных форматов, никаких ограничений в бесплатной версии, да и вообще – никакой платной версии нет в принципе.

Этот медиакомбайн будет хранить ваши фильмы и музыку на айфоне и сортировать их по категориям. Есть десятки тонких настроек аудио и видео, лаконичный интерфейс, поддержка воспроизведения файлов с Dropbox, GDrive, OneDrive, Box, iCloud Drive, iTunes, напрямую по ссылке, через общий Wi-Fi, а также трансляция файлов с SMB, FTP, SFTP, NFS, медиасерверов UPnP/DLNA и Интернета. Удобно и просто.

Хотя это единственный плеер в этой подборке, который всё-таки больше заточен под видео, чем аудио, его функционал и полная бесплатность без встроенных покупок позволяет конкурировать с остальными.

5. FLAC Player+. Самый лаконичный аудиоплеер

Этот бесплатный плеер поддерживает AAC и mp3, но главное легко переваривает музыку в несжатых форматах Flac. Из особенностей – есть возможность поставить в треке «закладку», чтобы начать воспроизведение с определённого места.

Кроме того, в приложении есть полноценный эквалайзер и удобная навигация по медиатеке.

FLAC Player+ визуально сильнее всех похож на Apple Music, так что разобраться в нём будет делом нескольких минут, интерфейс прост и понятен. Указываете путь к аудиофайлам на устройстве или запускаете синхронизацию песен из облака, вот и всё. В бесплатной версии плеера нет никаких ограничений, только присутствует реклама. Но это можно пережить ради музыки в студийном качестве.

Такой получился топ-5 аудиоплееров, которые совсем скоро (если не уже) поселятся в ваших айфонах. Для себя, после нескольких недель тестирования и сравнения, я выделил в фавориты плеер Flacbox, хотя вам может зайти любой другой. Пробуйте, тестируйте, а главное – слушайте хорошую музыку назло всем ограничениям.

Искусство должно принадлежать миру, и никак иначе.

Стриминг аудио в iOS на примере Яндекс.Диск

Во время работы над проектом по стримингу аудио необходимо было добавить поддержку новых сервисов, таких как Яндекс.Диск. Работа с аудио в приложении реализована через AVPlayer, который проигрывает файлы по url и поддерживает стандартные схемы, такие как file, http, https. Все работает отлично для сервисов, в которых токен авторизации передается в url запроса, среди них DropBox, Box, Google Drive. Для таких сервисов, как Яндекс.Диск, токен авторизации передается в заголовке запроса и к нему AVPlayer доступ не предоставляет.

Поиск решения этой проблемы среди имеющегося API привели к использованию объекта resourceLoader в AVURLAsset. С его помощью мы предоставляем доступ к файлу, размещенному на удаленном ресурсе, для AVPlayer. Работает это по принципу локального HTTP прокси но с максимальным упрощением для использования.

Нужно понимать что AVPlayer использует resourceLoader в тех случаях когда сам не знает как загрузить файл. Поэтому мы создаем url c кастумной схемой и инициализируем плеер с этим url. AVPlayer не зная как загрузить ресурс передает управление resourceLoader`y.

AVAssetResourceLoader работает через AVAssetResourceLoaderDelegate для которого нужно реализовать два метода:

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest; - (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest; 

Первый вызывается когда AVAssetResourceLoader начинает загрузку ресурса и передает нам AVAssetResourceLoadingRequest. В этом случае мы запоминаем запрос и начинаем загрузку данных. Если запрос уже не актуальный то AVAssetResourceLoader вызывает второй метод и мы отменяем загрузку данных.

Для начала создадим AVPlayer, используя url с кастумной схемой, назначим AVAssetResourceLoaderDelegate и очередь на которой будут вызываться методы делегата:

AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:@"customscheme://host/myfile.mp3"] options:nil]; [asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()]; AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:asset]; [self addObserversForPlayerItem:item]; self.player = [AVPlayer playerWithPlayerItem:playerItem]; [self addObserversForPlayer]; 

Заниматься загрузкой ресурса будет некий класс LSFilePlayerResourceLoader. Он инициализируется с url загружаемого ресурса и сессией YDSession, которая и будет непосредственно загружать файл с сервера. Хранить объекты LSFilePlayerResourceLoader мы будем в NSDictionary, а ключем будет url ресурса.

При загрузке ресурса с неизвестного источника AVAssetResourceLoader вызовет методы делегата.

AVAssetResourceLoaderDelegate

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest < NSURL *resourceURL = [loadingRequest.request URL]; if([resourceURL.scheme isEqualToString:@"customscheme"])< LSFilePlayerResourceLoader *loader = [self resourceLoaderForRequest:loadingRequest]; if(loader==nil)< loader = [[LSFilePlayerResourceLoader alloc] initWithResourceURL:resourceURL session:self.session]; loader.delegate = self; [self.resourceLoaders setObject:loader forKey:[self keyForResourceLoaderWithURL:resourceURL]]; >[loader addRequest:loadingRequest]; return YES; > return NO; > - (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest

В начале метода загрузки мы проверяем что схема соответствует нашей. Далее берем LSFilePlayerResourceLoader из кеша или создаем новый и добавляем к нему запрос на загрузку ресурса.

Интерфейс нашего LSFilePlayerResourceLoader выглядит так:

LSFilePlayerResourceLoader

 @interface LSFilePlayerResourceLoader : NSObject @property (nonatomic,readonly,strong)NSURL *resourceURL; @property (nonatomic,readonly)NSArray *requests; @property (nonatomic,readonly,strong)YDSession *session; @property (nonatomic,readonly,assign)BOOL isCancelled; @property (nonatomic,weak)id delegate; - (instancetype)initWithResourceURL:(NSURL *)url session:(YDSession *)session; - (void)addRequest:(AVAssetResourceLoadingRequest *)loadingRequest; - (void)removeRequest:(AVAssetResourceLoadingRequest *)loadingRequest; - (void)cancel; @end @protocol LSFilePlayerResourceLoaderDelegate @optional - (void)filePlayerResourceLoader:(LSFilePlayerResourceLoader *)resourceLoader didFailWithError:(NSError *)error; - (void)filePlayerResourceLoader:(LSFilePlayerResourceLoader *)resourceLoader didLoadResource:(NSURL *)resourceURL; @end 

Он содержит методы для добавления/удаления запроса в очередь и метод для отмены всех запросов. LSFilePlayerResourceLoaderDelegate сообщит когда ресурс полностью загружен или возникла ошибка при загрузке.

При добавлении запроса в очередь, вызовом addRequest, мы запоминаем его в pendingRequests и стартуем операцию загрузки данных:

Добавление запроса

- (void)addRequest:(AVAssetResourceLoadingRequest *)loadingRequest < if(self.isCancelled==NO)< NSURL *interceptedURL = [loadingRequest.request URL]; [self startOperationFromOffset:loadingRequest.dataRequest.requestedOffset length:loadingRequest.dataRequest.requestedLength]; [self.pendingRequests addObject:loadingRequest]; >else < if(loadingRequest.isFinished==NO)< [loadingRequest finishLoadingWithError:[self loaderCancelledError]]; >> > 

В начале мы создавали новую операцию загрузки данных для каждого поступающего запроса. В итоге получалось что файл загружался в три-четыре потока при этом данные пересекались. Но потом выяснили, что как только AVAssetResourceLoader начинает новый запрос предыдущие для него уже не актуальны. Это дает нам возможность смело отменять все выполняющиеся операции загрузки данных как только мы стартуем новую, что экономит трафик.

Операция загрузки данных с сервера разбита на две. Первая (contentInfoOperation) получает информацию о размере и типе файла. Вторая (dataOperation) — получает данные файла со смещением. Смещение и размер запрашиваемых данных мы вычитываем из объекта класса AVAssetResourceLoadingDataRequest.

Операция загрузки данных

- (void)startOperationFromOffset:(unsigned long long)requestedOffset length:(unsigned long long)requestedLength < [self cancelAllPendingRequests]; [self cancelOperations]; __weak typeof (self) weakSelf = self; void(^failureBlock)(NSError *error) = ^(NSError *error) < [weakSelf performBlockOnMainThreadSync:^< if(weakSelf && weakSelf.isCancelled==NO)< [weakSelf completeWithError:error]; >>]; >; void(^loadDataBlock)(unsigned long long off, unsigned long long len) = ^(unsigned long long offset,unsigned long long length)< [weakSelf performBlockOnMainThreadSync:^< NSString *bytesString = [NSString stringWithFormat:@"bytes=%lld-%lld",offset,(offset+length-1)]; NSDictionary *params = @; id req = [weakSelf.session partialContentForFileAtPath:weakSelf.path withParams:params response:nil data:^(UInt64 recDataLength, UInt64 totDataLength, NSData *recData) < [weakSelf performBlockOnMainThreadSync:^< if(weakSelf && weakSelf.isCancelled==NO)< LSDataResonse *dataResponse = [LSDataResonse responseWithRequestedOffset:offset requestedLength:length receivedDataLength:recDataLength data:recData]; [weakSelf didReceiveDataResponse:dataResponse]; >>]; > completion:^(NSError *err) < if(err)< failureBlock(err); >>]; weakSelf.dataOperation = req; >]; >; if(self.contentInformation==nil) < self.contentInfoOperation = [self.session fetchStatusForPath:self.path completion:^(NSError *err, YDItemStat *item) < if(weakSelf && weakSelf.isCancelled==NO)< if(err==nil)< NSString *mimeType = item.path.mimeTypeForPathExtension; CFStringRef contentType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType,(__bridge CFStringRef)(mimeType),NULL); unsigned long long contentLength = item.size; weakSelf.contentInformation = [[LSContentInformation alloc] init]; weakSelf.contentInformation.byteRangeAccessSupported = YES; weakSelf.contentInformation.contentType = CFBridgingRelease(contentType); weakSelf.contentInformation.contentLength = contentLength; [weakSelf prepareDataCache]; loadDataBlock(requestedOffset,requestedLength); weakSelf.contentInfoOperation = nil; >else < failureBlock(err); >> >]; > else < loadDataBlock(requestedOffset,requestedLength); >> 

После получения информации о файле на сервере мы создаем временный файл, в который будем записывать данные из сети и считывать их по мере надобности.

Инициализация дискового кеша

- (void)prepareDataCache < self.cachedFilePath = [[self class] pathForTemporaryFile]; NSError *error = nil; if ([[NSFileManager defaultManager] fileExistsAtPath:self.cachedFilePath] == YES)< [[NSFileManager defaultManager] removeItemAtPath:self.cachedFilePath error:&error]; >if (error == nil && [[NSFileManager defaultManager] fileExistsAtPath:self.cachedFilePath] == NO) < NSString *dirPath = [self.cachedFilePath stringByDeletingLastPathComponent]; [[NSFileManager defaultManager] createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:&error]; if (error == nil) < [[NSFileManager defaultManager] createFileAtPath:self.cachedFilePath contents:nil attributes:nil]; self.writingFileHandle = [NSFileHandle fileHandleForWritingAtPath:self.cachedFilePath]; @try < [self.writingFileHandle truncateFileAtOffset:self.contentInformation.contentLength]; [self.writingFileHandle synchronizeFile]; >@catch (NSException *exception) < NSError *error = [[NSError alloc] initWithDomain:LSFilePlayerResourceLoaderErrorDomain code:-1 userInfo:@]; [self completeWithError:error]; return; > self.readingFileHandle = [NSFileHandle fileHandleForReadingAtPath:self.cachedFilePath]; > > if (error != nil) < [self completeWithError:error]; >> 

После получения пакета данных мы сначала кешируем его на диск и обновляем размер полученных данных, хранимый в переменной receivedDataLength. В конце оповещаем запросы находящиеся в очереди о новой порции данных.

Получение пакета данных

- (void)didReceiveDataResponse:(LSDataResonse *)dataResponse

Метод кеширования записывает данные в файл с нужным смещением.

Кеширование данных

- (void)cacheDataResponse:(LSDataResonse *)dataResponse < unsigned long long offset = dataResponse.dataOffset; @try < [self.writingFileHandle seekToFileOffset:offset]; [self.writingFileHandle writeData:dataResponse.data]; [self.writingFileHandle synchronizeFile]; >@catch (NSException *exception) < NSError *error = [[NSError alloc] initWithDomain:LSFilePlayerResourceLoaderErrorDomain code:-1 userInfo:@]; [self completeWithError:error]; > > 

Метод чтения делает обратную операцию.

Чтение данных из кеша

- (NSData *)readCachedData:(unsigned long long)startOffset length:(unsigned long long)numberOfBytesToRespondWith < @try < [self.readingFileHandle seekToFileOffset:startOffset]; NSData *data = [self.readingFileHandle readDataOfLength:numberOfBytesToRespondWith]; return data; >@catch (NSException *exception) <> return nil; > 

Для оповещения запросов находящихся в очереди о новой порции данных мы сначала записываем информацию о контенте, а затем данные из кеша. Если все данные для запроса были записаны, то мы удаляем его из очереди.

Оповещение запросов

- (void)processPendingRequests < NSMutableArray *requestsCompleted = [[NSMutableArray alloc] init]; for (AVAssetResourceLoadingRequest *loadingRequest in self.pendingRequests)< [self fillInContentInformation:loadingRequest.contentInformationRequest]; BOOL didRespondCompletely = [self respondWithDataForRequest:loadingRequest.dataRequest]; if (didRespondCompletely)< [loadingRequest finishLoading]; [requestsCompleted addObject:loadingRequest]; >> [self.pendingRequests removeObjectsInArray:requestsCompleted]; > 

В методе заполнения информации о контенте мы устанавливаем размер, тип, флаг доступа к произвольному диапазону данных.

Заполнение информации о контенте

- (void)fillInContentInformation:(AVAssetResourceLoadingContentInformationRequest *)contentInformationRequest < if (contentInformationRequest == nil || self.contentInformation == nil)< return; >contentInformationRequest.byteRangeAccessSupported = self.contentInformation.byteRangeAccessSupported; contentInformationRequest.contentType = self.contentInformation.contentType; contentInformationRequest.contentLength = self.contentInformation.contentLength; > 

И основной метод, в котором мы считываем данные из кеша и передаем их запросам из очереди.

Заполнение данных

- (BOOL)respondWithDataForRequest:(AVAssetResourceLoadingDataRequest *)dataRequest < long long startOffset = dataRequest.requestedOffset; if (dataRequest.currentOffset != 0)< startOffset = dataRequest.currentOffset; >// Don't have any data at all for this request if (self.receivedDataLength < startOffset)< return NO; >// This is the total data we have from startOffset to whatever has been downloaded so far NSUInteger unreadBytes = self.receivedDataLength - startOffset; // Respond with whatever is available if we can't satisfy the request fully yet NSUInteger numberOfBytesToRespondWith = MIN(dataRequest.requestedLength, unreadBytes); BOOL didRespondFully = NO; NSData *data = [self readCachedData:startOffset length:numberOfBytesToRespondWith]; if(data)< [dataRequest respondWithData:data]; long long endOffset = startOffset + dataRequest.requestedLength; didRespondFully = self.receivedDataLength >= endOffset; > return didRespondFully; > 

На этом работа с загрузчиком закончена. Осталось немного изменить SDK Яндекс.Диска, для того чтобы мы могли загружать данные произвольного диапазона из файла на сервере. Изменений всего три.

Первое — нужно добавить для каждого запроса в YDSession возможность отмены. Для этого добавляем новый протокол YDSessionRequest и устанавливаем его в качестве возвращаемого значения в запросах.

YDSession.h

@protocol YDSessionRequest - (void)cancel; @end - (id)fetchDirectoryContentsAtPath:(NSString *)path completion:(YDFetchDirectoryHandler)block; - (id)fetchStatusForPath:(NSString *)path completion:(YDFetchStatusHandler)block; 

Второе — добавляем метод загрузки данных произвольного диапазона из файла на сервере.

YDSession.h

- (id)partialContentForFileAtPath:(NSString *)srcRemotePath withParams:(NSDictionary *)params response:(YDDidReceiveResponseHandler)response data:(YDPartialDataHandler)data completion:(YDHandler)completion; 

YDSession.m

- (id)partialContentForFileAtPath:(NSString *)srcRemotePath withParams:(NSDictionary *)params response:(YDDidReceiveResponseHandler)response data:(YDPartialDataHandler)data completion:(YDHandler)completion < return [self downloadFileFromPath:srcRemotePath toFile:nil withParams:params response:response data:data progress:nil completion:completion]; >- (id)downloadFileFromPath:(NSString *)path toFile:(NSString *)aFilePath withParams:(NSDictionary *)params response:(YDDidReceiveResponseHandler)responseBlock data:(YDPartialDataHandler)dataBlock progress:(YDProgressHandler)progressBlock completion:(YDHandler)completionBlock< NSURL *url = [YDSession urlForDiskPath:path]; if (!url) < completionBlock([NSError errorWithDomain:kYDSessionBadArgumentErrorDomain code:0 userInfo:@]); return nil; > BOOL skipReceivedData = NO; if(aFilePath==nil) < aFilePath = [[self class] pathForTemporaryFile]; skipReceivedData = YES; >NSURL *filePath = [YDSession urlForLocalPath:aFilePath]; if (!filePath) < completionBlock([NSError errorWithDomain:kYDSessionBadArgumentErrorDomain code:1 userInfo:@]); return nil; > YDDiskRequest *request = [[YDDiskRequest alloc] initWithURL:url]; request.fileURL = filePath; request.params = params; request.skipReceivedData = skipReceivedData; [self prepareRequest:request]; NSURL *requestURL = [request.URL copy]; request.callbackQueue = _callBackQueue; request.didReceiveResponseBlock = ^(NSURLResponse *response, BOOL *accept) < if(responseBlock)< responseBlock(response); >>; request.didGetPartialDataBlock = ^(UInt64 receivedDataLength, UInt64 expectedDataLength, NSData *data) < if(progressBlock)< progressBlock(receivedDataLength,expectedDataLength); >if(dataBlock) < dataBlock(receivedDataLength,expectedDataLength,data); >>; request.didFinishLoadingBlock = ^(NSData *receivedData) < if(skipReceivedData)< [[self class] removeTemporaryFileAtPath:aFilePath]; >NSDictionary *userInfo = @; [[NSNotificationCenter defaultCenter] postNotificationInMainQueueWithName:kYDSessionDidDownloadFileNotification object:self userInfo:userInfo]; completionBlock(nil); >; request.didFailBlock = ^(NSError *error) < if(skipReceivedData)< [[self class] removeTemporaryFileAtPath:aFilePath]; >NSDictionary *userInfo = @; [[NSNotificationCenter defaultCenter] postNotificationInMainQueueWithName:kYDSessionDidFailToDownloadFileNotification object:self userInfo:userInfo]; completionBlock([NSError errorWithDomain:error.domain code:error.code userInfo:userInfo]); >; [request start]; NSDictionary *userInfo = @; [[NSNotificationCenter defaultCenter] postNotificationInMainQueueWithName:kYDSessionDidStartDownloadFileNotification object:self userInfo:userInfo]; return (id)request; > 

И третье, что нужно исправить — это изменить очередь колбеков с параллельной на последовательную, иначе блоки данных будут приходить не в том порядке, в котором мы запрашивали, и пользователь будет слышать рывки при проигрывании музыки.

YDSession.m

- (instancetype)initWithDelegate:(id)delegate callBackQueue:(dispatch_queue_t)queue < self = [super init]; if (self) < _delegate = delegate; _callBackQueue = queue; >return self; > YDDiskRequest *request = [[YDDiskRequest alloc] initWithURL:url]; request.fileURL = filePath; request.params = params; [self prepareRequest:request]; request.callbackQueue = _callBackQueue; 

Исходный код примера на GitHub.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *