Prerequisites:
Packages:
Steps:
flutter pub add audioplayers srt_parser_2 http
2. Create the UI:
3. Fetch audio and subtitle files:
- Implement functions to fetch the audio and subtitle files from their network locations using the
http
package. Handle potential errors and provide feedback to the user.
4. Parse subtitles:
- Use the
srt_parser_2
package to parse the downloaded subtitle file into a list ofSrtSubtitle
objects, which contain start and end times for each subtitle text.
5. Create an AudioPlayer instance:
- Instantiate an
AudioPlayer
object:
AudioPlayer audioPlayer = AudioPlayer();
Use a Stream
or Timer
to periodically check the audio player’s current position:
Stream<Duration> positionStream = audioPlayer.onAudioPositionChanged;
positionStream.listen((position) {
// Find the current subtitle based on the audio position
SrtSubtitle? currentSubtitle = findCurrentSubtitle(position, subtitles);
// If a subtitle is found, update the display
if (currentSubtitle != null) {
setState(() {
currentSubtitleText = currentSubtitle.text;
});
// Scroll the subtitle list to the current item if necessary
// (implementation depends on your chosen scrollable widget)
}
});
Dispose of resources:
@override
void dispose() {
audioPlayer.dispose();
super.dispose();
}
Complete code example:
import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:srt_parser_2/srt_parser_2.dart';
import 'package:http/http.dart' as http;
class AudioPlayerWithSubtitles extends StatefulWidget {
final String audioUrl;
final String subtitleUrl;
const AudioPlayerWithSubtitles({Key? key, required this.audioUrl, required this.subtitleUrl}) : super(key: key);
@override
_AudioPlayerWithSubtitlesState createState() => _AudioPlayerWithSubtitlesState();
}
class _AudioPlayerWithSubtitlesState extends State<AudioPlayerWithSubtitles> {
String currentSubtitleText = '';
List<SrtSubtitle> subtitles = [];
AudioPlayer audioPlayer = AudioPlayer();
@override
void initState() {
super.initState();
_fetchSubtitles();
_playAudio();
}
void _fetchSubtitles() async {
try {
final response = await http.get(Uri.parse(widget.subtitleUrl));
if (response.statusCode == 200) {
final srtContent = response.body;
subtitles = parseSrt(srtContent);
} else {
// Handle error
}
} catch (error) {
// Handle error
}
}
void _playAudio() async {
try {
await audioPlayer.play(widget.audioUrl);
final positionStream = audioPlayer.onAudioPositionChanged;
positionStream.listen((position) {
Here’s the findCurrentSubtitle
method you can use to identify the current subtitle based on the audio position:
SrtSubtitle? findCurrentSubtitle(Duration position, List<SrtSubtitle> subtitles) {
for (final subtitle in subtitles) {
if (position >= subtitle.startTime && position <= subtitle.endTime) {
return subtitle;
}
}
return null; // No matching subtitle found
}
This method iterates through the list of SrtSubtitle
objects and compares the audio position (position
) with the startTime
and endTime
of each subtitle. If the position falls within the time range of a subtitle, that subtitle is returned. Otherwise, null
is returned, indicating that no matching subtitle was found.
Explanation:
Remember to integrate this method within the positionStream
listener to update the displayed subtitle as the audio progresses.
Scrolling the list view to the current subtitle
Scrolling the list view to the current subtitle can be achieved by adding some logic to your findCurrentSubtitle
method and your scrollable widget. Here’s how you can do it:
1. Modifying findCurrentSubtitle
:
Instead of just returning the SrtSubtitle
object, we can enhance it to include the scroll index of the corresponding subtitle in the list view:
SrtSubtitleWithIndex? findCurrentSubtitle(Duration position, List<SrtSubtitle> subtitles) {
for (int i = 0; i < subtitles.length; i++) {
final subtitle = subtitles[i];
if (position >= subtitle.startTime && position <= subtitle.endTime) {
return SrtSubtitleWithIndex(subtitle: subtitle, index: i);
}
}
return null; // No matching subtitle found
}
his modified method now creates a SrtSubtitleWithIndex
object that holds both the SrtSubtitle
and its corresponding index in the list view.
2. Integrating with Scrollable Widget:
Next, update your positionStream
listener to utilize the scroll index information:
positionStream.listen((position) {
final currentSubtitleWithIndex = findCurrentSubtitle(position, subtitles);
if (currentSubtitleWithIndex != null) {
setState(() {
currentSubtitleText = currentSubtitleWithIndex.subtitle.text;
});
// Scroll the list view to the appropriate item
_scrollToItem(currentSubtitleWithIndex.index);
}
});
You’ll need to implement the _scrollToItem
method based on your chosen scrollable widget:
For ListView.builder
:
void _scrollToItem(int index) {
// Use a ScrollController to control the list view
final controller = ScrollController();
// Calculate the item's offset based on its index and estimated item height
final offset = index * estimatedItemHeight;
// Animate the scroll to the desired offset
controller.animateTo(offset,
duration: const Duration(milliseconds: 300), curve: Curves.easeInOut);
}
Replace estimatedItemHeight
with the actual or estimated height of your subtitle items.
For other scrollable widgets, use their respective scrolling APIs.
Remember to dispose of the ScrollController
when the widget is no longer needed.
Additional considerations:
By following these steps, you can effectively scroll your list view to the current subtitle as the audio plays, enhancing the user experience of your audio player with subtitles.
We recommend AutoSizeText to display subtitle. Because if set estimatedItemHeight=100 then AutoSizeText will try its best to fit the text into that height this is what we want.
Row(
children: <Widget>[
Expanded(
// Constrains AutoSizeText to the width of the Row
child: AutoSizeText(
subtitle.rawLines.join(),
minFontSize: 16,
maxFontSize: 20,
maxLines: 10,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: subtitle == _currentSubtitle ? 20 : 16,
fontWeight: subtitle == _currentSubtitle
? FontWeight.w900
: FontWeight.w500,
color: subtitle == _currentSubtitle
? Colors.black
: Colors.grey,
shadows: StringUtils.getGoldenShadow(),
),
))
],
)
Thanks for reading the post.Hope it has help you to get the idea to implement the Audio player in Flutter with Subtitles