Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic header generation with AudioSource.uri #967

Closed
nagataaaas opened this issue Apr 1, 2023 · 3 comments
Closed

Dynamic header generation with AudioSource.uri #967

nagataaaas opened this issue Apr 1, 2023 · 3 comments
Assignees
Labels
1 backlog enhancement New feature or request

Comments

@nagataaaas
Copy link

nagataaaas commented Apr 1, 2023

maybe related

Is your feature request related to a problem? Please describe.
I'm trying to play some online music that needs custom header that includes "Request Timestamp" and "Signature created with Timestamp and access/secret key"(just like this implementation).
When I try to play single song with setUrl like AudioPlayer.setUrl(url, headers: generateSignedHeaders(url)), works pretty good.

But if I set playlist as a audio source, latter music's header will be expired and unable to listen. Off course, if I play back to the first track of the playlist from second one, It's already expired.

Describe the solution you'd like
I'd love to have an argument which evaluate header just the time loading starting like below

final url = 'https://some.api.com/audio_needs_signature.mp3';
final playlist = ConcatenatingAudioSource(children: [
  AudioSource.uri(Uri.parse(url),
  headerCreator: () => createCredential(url: url, time: DateTime.now()),
]);
_audioPlayer.setAudioSource(playlist)

Describe alternatives you've considered
Or, custom subclass of Playlist can be great like

// this doesn't work at all
class CustomLazyPlaylist extends ConcatenatingAudioSource {
  int get length => 3;
  final List<String> paths;
  Map<String, String> Function() headerCreator;

  CustomLazyPlaylist(this.paths, this.headerCreator);

  AudioSource getCurrentAudio(int index) {
    return AudioSource.uri(
      Uri.parse(paths[index]),
      headers: headerCreator(),
    );
  }

  List<AudioSource> get children {
    return List.generate(length, (index) => getCurrentAudio(index));
  }
}

Additional context
Add any other context or screenshots about the feature request here.
Thanks for such a great plugin. I hope this Feature request will be accepted soon and bring a nice change to this plugin.

@nagataaaas
Copy link
Author

I'm sorry, this may me the duplicate of #777

@nagataaaas
Copy link
Author

after watching #800, this code works on branch minor.

import 'dart:async';
import 'dart:io';

import 'package:just_audio/just_audio.dart';
import 'package:just_audio_platform_interface/just_audio_platform_interface.dart'
    show AudioSourceMessage, ProgressiveAudioSourceMessage;

class ResolvingAudioSource extends StreamAudioSource {
  final String uniqueId;
  final Uri url;
  final Map<String, String> Function() headersCreater;

  HttpClient? _httpClient;

  HttpClient get httpClient => _httpClient ?? (_httpClient = HttpClient());

  ResolvingAudioSource(
      {required this.uniqueId,
      required this.url,
      required this.headersCreater,
      dynamic tag})
      : super(tag: tag);

  @override
  Future<StreamAudioResponse> request([int? start, int? end]) async {
    final request = await httpClient.getUrl(url);

    for (var entry in headersCreater().entries) {
      request.headers.set(entry.key, entry.value);
    }
    if (start != null || end != null) {
      request.headers
          .set(HttpHeaders.rangeHeader, 'bytes=${start ?? ""}-${end ?? ""}');
    }
    final response = await request.close();
    final acceptRangesHeader =
        response.headers.value(HttpHeaders.acceptRangesHeader);
    final contentRange = response.headers.value(HttpHeaders.contentRangeHeader);
    int? offset;
    if (contentRange != null) {
      int offsetEnd = contentRange.indexOf('-');
      if (offsetEnd >= 6) {
        offset = int.tryParse(contentRange.substring(6, offsetEnd));
      }
    }
    final contentLength =
        response.headers.value(HttpHeaders.contentLengthHeader);
    final contentType = response.headers.value(HttpHeaders.contentTypeHeader);
    return StreamAudioResponse(
        rangeRequestsSupported:
            acceptRangesHeader != null && acceptRangesHeader != 'none',
        sourceLength: null,
        contentLength:
            contentLength == null ? null : int.tryParse(contentLength),
        offset: offset,
        stream: response.asBroadcastStream(),
        contentType: contentType ?? "");
  }

  @override
  AudioSourceMessage _toMessage() {
    return ProgressiveAudioSourceMessage(
        id: uniqueId, uri: url.toString(), headers: headersCreater(), tag: tag);
  }
}

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs, or use StackOverflow if you need help with just_audio.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 16, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
1 backlog enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants