使用 react-native-track-player 从 Napster API 流式传输歌曲
Posted
技术标签:
【中文标题】使用 react-native-track-player 从 Napster API 流式传输歌曲【英文标题】:Using react-native-track-player To A Streaming Songs From Napster API 【发布时间】:2021-03-31 03:59:05 【问题描述】:我按照教程使用 react-native-track-player 构建了一个简单的音乐播放器,这是我在 react native 学习曲线的一部分。现在,我不只是从我的歌曲数组中提供的 url 曲目播放/流式播放歌曲,我想从 API 流式传输歌曲(尽管它可以是任何 API - 但我已经注册了 Napster API),我觉得不受限制只有几首歌。但是,我无法将如何实现或调用 Napster API 来获取歌曲放在一起。 请任何帮助/指导,我将不胜感激。
下面是我的代码:
我有 data.js,我的歌曲数组:
const songs = [
title: "death bed",
artist: "Powfu",
artwork: require("../assets/album-arts/death-bed.jpg"),
url: "https://github.com/ShivamJoker/sample-songs/raw/master/death%20bed.mp3",
id: "1",
,
title: "bad liar",
artist: "Imagine Dragons",
artwork: require("../assets/album-arts/bad-liar.jpg"),
url: "https://github.com/ShivamJoker/sample-songs/raw/master/Bad%20Liar.mp3",
id: "2",
,
title: "faded",
artist: "Alan Walker",
artwork: require("../assets/album-arts/faded.jpg"),
url: "https://github.com/ShivamJoker/sample-songs/raw/master/Faded.mp3",
id: "3",
,
];
export default songs;
这是我的 playerScreen.js :
import React, useRef, useEffect, useState from 'react';
import
View,
SafeAreaView,
Text,
Image,
FlatList,
Dimensions,
Animated,
StyleSheet,
from 'react-native';
import TrackPlayer,
Capability,
useTrackPlayerEvents,
usePlaybackState,
TrackPlayerEvents,
STATE_PLAYING,
Event,
from 'react-native-track-player';
import songs from './data';
import Controller from './Controller';
import SliderComp from './SliderComp';
const width, height = Dimensions.get('window');
// const events = [
// TrackPlayerEvents.PLAYBACK_STATE,
// TrackPlayerEvents.PLAYBACK_ERROR
// ];
export default function PlayerScreen()
const scrollX = useRef(new Animated.Value(0)).current;
const slider = useRef(null);
const isPlayerReady = useRef(false);
const index = useRef(0);
const [songIndex, setSongIndex] = useState(0);
const isItFromUser = useRef(true);
// for tranlating the album art
const position = useRef(Animated.divide(scrollX, width)).current;
const playbackState = usePlaybackState();
useEffect(() =>
// position.addListener(( value ) =>
// console.log(value);
// );
scrollX.addListener((value) =>
const val = Math.round(value / width);
setSongIndex(val);
);
TrackPlayer.setupPlayer().then(async () =>
// The player is ready to be used
console.log('Player ready');
// add the array of songs in the playlist
await TrackPlayer.reset();
await TrackPlayer.add(songs);
TrackPlayer.play();
isPlayerReady.current = true;
await TrackPlayer.updateOptions(
stopWithApp: false,
alwaysPauseOnInterruption: true,
capabilities: [
Capability.Play,
Capability.Pause,
Capability.SkipToNext,
Capability.SkipToPrevious,
],
);
//add listener on track change
TrackPlayer.addEventListener(Event.PlaybackTrackChanged, async (e) =>
console.log('song ended', e);
const trackId = (await TrackPlayer.getCurrentTrack()) - 1; //get the current id
console.log('track id', trackId, 'index', index.current);
if (trackId !== index.current)
setSongIndex(trackId);
isItFromUser.current = false;
if (trackId > index.current)
goNext();
else
goPrv();
setTimeout(() =>
isItFromUser.current = true;
, 200);
// isPlayerReady.current = true;
);
//monitor intterupt when other apps start playing music
TrackPlayer.addEventListener(Event.RemoteDuck, (e) =>
// console.log(e);
if (e.paused)
// if pause true we need to pause the music
TrackPlayer.pause();
else
TrackPlayer.play();
);
);
return () =>
scrollX.removeAllListeners();
TrackPlayer.destroy();
// exitPlayer();
;
, []);
// change the song when index changes
useEffect(() =>
if (isPlayerReady.current && isItFromUser.current)
TrackPlayer.skip(songs[songIndex].id)
.then((_) =>
console.log('changed track');
)
.catch((e) => console.log('error in changing track ', e));
index.current = songIndex;
, [songIndex]);
const exitPlayer = async () =>
try
await TrackPlayer.stop();
catch (error)
console.error('exitPlayer', error);
;
const goNext = async () =>
slider.current.scrollToOffset(
offset: (index.current + 1) * width,
);
await TrackPlayer.play();
;
const goPrv = async () =>
slider.current.scrollToOffset(
offset: (index.current - 1) * width,
);
await TrackPlayer.play();
;
const renderItem = (index, item) =>
return (
<Animated.View
style=
alignItems: 'center',
width: width,
transform: [
translateX: Animated.multiply(
Animated.add(position, -index),
-100,
),
,
],
>
<Animated.Image
source=item.artwork
style=width: 320, height: 320, borderRadius: 5
/>
</Animated.View>
);
;
return (
<SafeAreaView style=styles.container>
<SafeAreaView style=height: 320>
<Animated.FlatList
ref=slider
horizontal
pagingEnabled
showsHorizontalScrollIndicator=false
scrollEventThrottle=16
data=songs
renderItem=renderItem
keyExtractor=(item) => item.id
onScroll=Animated.event(
[nativeEvent: contentOffset: x: scrollX],
useNativeDriver: true,
)
/>
</SafeAreaView>
<View>
<Text style=styles.title>songs[songIndex].title</Text>
<Text style=styles.artist>songs[songIndex].artist</Text>
</View>
<SliderComp />
<Controller onNext=goNext onPrv=goPrv />
</SafeAreaView>
);
【问题讨论】:
【参考方案1】:我会通过道具将songs
传递给您当前的PlayerScreen
。您可以使用单独的组件从 Napster API 加载曲目,然后使用这些道具渲染 PlayerScreen
。
我唯一不确定的部分是作为url
传递给玩家的路径。 Napster 数据包含一个属性previewURL
,它是一个mp3
,但它不是整首歌。我相信 href
是可流式传输的 URL。不过,它需要身份验证才能加载完整曲目。
我在这里使用的 API 路径适用于最流行的曲目。
export default function TopTracks()
const [songs, setSongs] = useState([]);
useEffect(() =>
const loadData = async () =>
try
const url = `http://api.napster.com/v2.2/tracks/top?apikey=$API_KEY&limit=5`;
const res = await axios.get(url);
setSongs(
res.data.tracks.map((track) => (
duration: track.playbackSeconds,
title: track.name,
artist: track.artistName,
album: track.albumName,
id: track.id,
url: track.href // or track.previewURL?
))
);
catch (error)
console.error(error);
;
loadData();
, []);
return <PlayerScreen songs=songs />;
【讨论】:
非常感谢您的回复。我似乎不明白您所说的“我会通过道具将歌曲传递到您当前的 PlayerScreen ”是什么意思。因为包含歌曲数组的文件 data.js 仍然存在。以上是关于使用 react-native-track-player 从 Napster API 流式传输歌曲的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?
Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)