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

feat: marquee song title #226

Merged
merged 16 commits into from
Nov 7, 2023
13 changes: 11 additions & 2 deletions .github/workflows/android-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,11 @@ jobs:
files: android/app/build/outputs/apk/release/*.apk
generate_release_notes: true

- name: Push changes to master
uses: ad-m/github-push-action@master
- name: codepush to prod
run: |
npm install -g appcenter-cli
yarn codepush --token ${{secrets.CODEPUSH_ACCESS_TOKEN}}
yarn codepush:promote --token ${{secrets.CODEPUSH_ACCESS_TOKEN}}

buildAAB:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -190,6 +193,12 @@ jobs:
track: internal
# status: draft

- name: git pull
run: git pull

- name: Push changes to master
uses: ad-m/github-push-action@master

buildIPA:
runs-on: macos-12
name: build IPA
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@
市面上有很多播放器竞品,比如整合大量音乐网站,跨平台的[~listen1~](https://github.com/listen1/listen1_chrome_extension)、[~洛雪音乐~](https://github.com/lyswhut/lx-music-mobile)、[musicfree](https://github.com/maotoumao/MusicFree);动画elegent的[namida](https://github.com/namidaco/namida);界面简洁好使的本地播放器[AIMP](https://www.aimp.ru/);支持b站的也不是没有,为什么要用管人播放器?

- 管人播放器之初为了溜阿梓歌切收藏夹而诞生,自从持久、稳定、每日投分p的第五代阿梓切歌人[HonmaMeiko](https://space.bilibili.com/590096/video?tid=0&keyword=&order=pubdate)接棒后,以及[自动切歌软件](https://www.bilibili.com/video/BV1WK411y7zW/?spm_id_from=333.999.0.0)研发成功可以大批量无人值守切各种没人切的管人歌势,管人播放器开发了对b站视频列表的支持,以及订阅b站链接的功能,专注于解决b站视频分p搜索孱弱,整合视频分p、视频列表、视频合集、收藏夹、空间~b站产品经理脑门被夹了搞这么多一样的玩意儿~等多种视频列表为一个统一的歌单。由于b站音乐区本身流量不足~依托答辩~,大多整合类播放器对于b站的支持很基础,并没有管人播放器类别支持广,没有订阅功能,也不整合b站增加播放量、点赞等操作。
- 绝大部分播放器不支持歌单订阅功能。
- 没有可以给管人痴定制皮肤的播放器。
- 绑ffmpeg做OTF音量均衡,和用RN做Android Auto适配的播放器仅此一家。
- 管人播放器支持歌单订阅。
- 管人播放器给管人痴定制皮肤。
- 管人播放器绑ffmpeg做OTF音量均衡.
- 管人播放器有业界领先的React Native Android Auto适配。

## 安装

Expand Down
16 changes: 0 additions & 16 deletions android/app/src/main/java/com/noxplay/noxplayer/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,4 @@ public void onPictureInPictureModeChanged (boolean isInPictureInPictureMode, Con
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
}

@Override
public void onPause() {
// If called while in PiP mode, do not pause playback
super.onPause();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (isInPictureInPictureMode()) {
// Continue playback
// for some reason my S21 doesn't trigger this at all. pixel is fine.
} else {
// Use existing playback logic for paused Activity behavior.
}
} else {

}
}

}
14 changes: 8 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@
"codepush": "appcenter codepush release-react -a lovegaoshi/Azusa-Player-Mobile",
"codepush:rollback": "appcenter codepush rollback -a lovegaoshi/Azusa-Player-Mobile Production",
"codepush:promote": "appcenter codepush promote -a lovegaoshi/Azusa-Player-Mobile -s Staging -d Production",
"dep": "yarn upgrade-interactive --latest",
"release": "git switch master; git pull; python release_bump.py"
},
"dependencies": {
"@react-native-async-storage/async-storage": "^1.18.1",
"@react-native-community/netinfo": "^9.3.10",
"@react-native-async-storage/async-storage": "^1.19.4",
"@react-native-community/netinfo": "^10.0.0",
"@react-native-cookies/cookies": "git+https://github.com/alexhernandez/cookies.git#patch-1",
"@react-native/metro-config": "^0.74.0",
"@react-navigation/drawer": "^6.6.2",
"@react-navigation/material-top-tabs": "^6.6.2",
"@react-navigation/native": "^6.1.6",
"@react-navigation/native-stack": "^6.9.12",
"@react-navigation/native-stack": "^6.9.17",
"@sharcoux/slider": "^7.0.5",
"@shopify/flash-list": "^1.4.3",
"axios": "^1.4.0",
Expand Down Expand Up @@ -87,17 +88,18 @@
"react-native-svg": "^13.9.0",
"react-native-svga-player": "git+https://[email protected]/lovegaoshi/react-native-svga-player.git",
"react-native-tab-view": "^3.5.1",
"react-native-text-ticker": "^1.14.0",
"react-native-track-player": "git+https://[email protected]/lovegaoshi/react-native-track-player.git#APM",
"react-native-url-polyfill": "^2.0.0",
"react-native-vector-icons": "^10.0.1",
"react-native-video": "^6.0.0-alpha.8",
"react-native-webview": "^13.3.0",
"react-native-windows": "^0.72.17",
"react-native-windows": "^0.72.18",
"react-use": "^17.4.0",
"use-debounce": "^9.0.4",
"uuid": "^9.0.0",
"ytdl-core": "git+https://[email protected]/lovegaoshi/node-ytdl-core.git",
"zustand": "^4.4.5"
"zustand": "^4.4.6"
},
"resolutions": {
"metro": "^0.80.0"
Expand All @@ -112,7 +114,7 @@
"@types/jest": "^29.5.7",
"@types/md5": "^2.3.2",
"@types/node": "^20.8.10",
"@types/react": "^18.0.24",
"@types/react": "^18.2.34",
"@types/react-native": "^0.72.5",
"@types/react-native-background-timer": "^2.0.0",
"@types/react-native-share-menu": "^5.0.2",
Expand Down
8 changes: 4 additions & 4 deletions src/AzusaPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import DummySettings from './components/setting/DummySettings';
import './localization/i18n';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ICONS } from '@enums/Icons';
import NoxAndroidBottomTab from './components/bottomtab/NoxBottomTab';
import NoxBottomTab from './components/bottomtab/NoxBottomTab';

const { LightTheme, DarkTheme } = adaptNavigationTheme({
reactNavigationLight: NavigationDefaultTheme,
Expand Down Expand Up @@ -83,7 +83,7 @@ const AzusaPlayer = () => {
DrawerNavigationProp<ParamListBase> | undefined
>(undefined);

const NoxPlayer2 = ({ navigation }: Props) =>
const NoxPlayerWrapper = ({ navigation }: Props) =>
NoxPlayer({ navigation, setNavigation });

return (
Expand Down Expand Up @@ -125,7 +125,7 @@ const AzusaPlayer = () => {
title: String(t('appDrawer.homeScreenName')),
header: () => null,
}}
component={NoxPlayer2}
component={NoxPlayerWrapper}
/>
<Drawer.Screen
name={ViewEnum.EXPORE}
Expand All @@ -145,7 +145,7 @@ const AzusaPlayer = () => {
component={Settings}
/>
</Drawer.Navigator>
<NoxAndroidBottomTab navigation={navigation} />
<NoxBottomTab navigation={navigation} />
</View>
</NavigationContainer>
</PaperProvider>
Expand Down
3 changes: 1 addition & 2 deletions src/components/background/MainBackground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,11 @@ export const resolveBackgroundImage = async (
await fetchVideoPlayUrlPromise({
bvid: backgroundImage.identifier,
extractType: 'VideoUrl',
iOS: Platform.OS === 'ios',
//. iOS: Platform.OS === 'ios',
})
).url,
};
case RESOLVE_TYPE.biliNFTVideo:
// eslint-disable-next-line no-case-declarations
const [act_id, index] = JSON.parse(backgroundImage.identifier);
return {
type: RESOLVE_TYPE.video,
Expand Down
3 changes: 2 additions & 1 deletion src/components/bottomtab/NoxBottomTab.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { StyleSheet, View, Platform } from 'react-native';
import { IconButton } from 'react-native-paper';
import { useNavigation, ParamListBase } from '@react-navigation/native';
import {
Expand Down Expand Up @@ -103,6 +103,7 @@ const NoxAndroidBottomTab = ({ navigation }: Props) => {
const styles = StyleSheet.create({
panel: {
flexDirection: 'row',
paddingBottom: Platform.OS === 'ios' ? 20 : 0,
},
iconButton: {
flex: 1,
Expand Down
30 changes: 27 additions & 3 deletions src/components/dialogs/CopiedPlaylistDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { useTranslation } from 'react-i18next';

import { useNoxSetting } from '@hooks/useSetting';
import logger from '@utils/Logger';
import noxPlayingList from '@stores/playingList';
import { NoxRepeatMode } from '@enums/RepeatMode';

const { getState } = noxPlayingList;

interface Props {
visible: boolean;
Expand All @@ -21,6 +25,7 @@ export default ({
}: Props) => {
const { t } = useTranslation();
const [playlistIndex, setPlaylistIndex] = useState('');
const playlistRef = React.useRef<FlatList<string[]>>(null);
const playlistIds = useNoxSetting(state => state.playlistIds);
const playlists = useNoxSetting(state => state.playlists);
const updatePlaylist = useNoxSetting(state => state.updatePlaylist);
Expand All @@ -43,6 +48,26 @@ export default ({
onSubmit();
};

const playlistList = () => {
const filteredPlaylists =
getState().playmode === NoxRepeatMode.SUGGEST
? playlistIds
: playlistIds.filter(val => val !== fromList.id);
return filteredPlaylists.map(val => [val, playlists[val].title]);
};


React.useEffect(() => {

// TODO: this is not scrolling?
if (visible && getState().playmode === NoxRepeatMode.SUGGEST) {
playlistRef.current?.scrollToIndex({
index: playlistIds.indexOf(fromList.id),
})
setPlaylistIndex(fromList.id);
}
}, [visible])

return (
<Portal>
<Dialog visible={visible} onDismiss={handleClose} style={styles.dialog}>
Expand All @@ -57,9 +82,8 @@ export default ({
<Dialog.Content style={styles.dialogContent}>
<FlatList
style={styles.dialogList}
data={playlistIds
.filter(val => val !== fromList.id)
.map(val => [val, playlists[val].title])}
data={playlistList()}
ref={playlistRef}
renderItem={({ item }) => (
<Pressable
onPress={() => setPlaylistIndex(item[0])}
Expand Down
2 changes: 1 addition & 1 deletion src/components/player/Lyric.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Lrc as Lyric } from 'react-native-lyric';
import { Track, useProgress } from 'react-native-track-player';
import { IconButton, TextInput } from 'react-native-paper';

import { searchLyricOptions, searchLyric } from '@utils/Data';
import { searchLyricOptions, searchLyric } from '@utils/LyricFetch';
import { reExtractSongName } from '@stores/appStore';
import { useNoxSetting } from '@hooks/useSetting';
import { logger } from '@utils/Logger';
Expand Down
2 changes: 1 addition & 1 deletion src/components/player/TrackInfo/TrackInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const TrackInfo: React.FC<Props> = ({ track, windowWidth }) => {

const styles = StyleSheet.create({
albumArt: {
paddingTop: 10,
paddingTop: 15,
},
});

Expand Down
16 changes: 13 additions & 3 deletions src/components/player/TrackInfo/TrackInfoTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
Animated,
TouchableWithoutFeedback,
ViewStyle,
Easing,
} from 'react-native';
import type { Track } from 'react-native-track-player';
import { Image } from 'expo-image';
import MarqueeText from 'react-native-text-ticker';

import { useNoxSetting } from '@hooks/useSetting';
import { getCurrentTPQueue } from '@stores/playingList';
Expand Down Expand Up @@ -88,7 +90,15 @@ const TrackInfoTemplate: React.FC<Props> = ({
return (
<View style={[styles.container, containerStyle, { width: windowWidth }]}>
{children || <AlbumArt />}
<Text style={textStyle}>{track?.title}</Text>
<MarqueeText
duration={3000}
animationType={'bounce'}
bounceDelay={2000}
style={textStyle}
easing={Easing.linear}
>
{track?.title}
</MarqueeText>
<View style={styles.infoContainer}>
<View style={styles.favoriteButtonContainer}>
<FavReloadButton track={track} />
Expand Down Expand Up @@ -138,7 +148,7 @@ const styles = StyleSheet.create({
flex: 1,
// justifyContent: 'center',
alignItems: 'center',
marginTop: -10,
marginTop: -5,
},
artistInfoContainer: {
flex: 4,
Expand All @@ -149,6 +159,6 @@ const styles = StyleSheet.create({
flex: 1,
// justifyContent: 'center',
alignItems: 'center',
marginTop: -10,
marginTop: -5,
},
});
56 changes: 55 additions & 1 deletion src/components/player/usePlayerControls.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
import { useTrackPlayerEvents, Event } from 'react-native-track-player';
import React from 'react';
import TrackPlayer, {
useTrackPlayerEvents,
Event,
State,
} from 'react-native-track-player';

import { useNoxSetting } from '@hooks/useSetting';
import useTPControls from '@hooks/useTPControls';
import { saveLastPlayDuration } from '@utils/ChromeStorage';
import { logger } from '@utils/Logger';
import appStore, { getABRepeatRaw, setCurrentPlaying } from '@stores/appStore';
import noxPlayingList from '@stores/playingList';
import { NoxRepeatMode } from '@enums/RepeatMode';
import { fadePlay } from '@utils/RNTPUtils';

const { getState } = noxPlayingList;
const { fadeIntervalMs, fadeIntervalSec } = appStore.getState();

export default () => {
const { performSkipToNext, performSkipToPrevious } = useTPControls();
const [abRepeat, setABRepeat] = React.useState<[number, number]>([0, 1]);
const [bRepeatDuration, setBRepeatDuration] = React.useState(9999);
const setCurrentPlayingId = useNoxSetting(state => state.setCurrentPlayingId);

useTrackPlayerEvents([Event.PlaybackActiveTrackChanged], event => {
Expand All @@ -25,6 +41,44 @@ export default () => {
performSkipToPrevious();
});

useTrackPlayerEvents([Event.PlaybackProgressUpdated], event => {
saveLastPlayDuration(event.position);
if (
event.duration > 0 &&
event.position >
Math.min(bRepeatDuration, event.duration) - fadeIntervalSec
) {
if (getState().playmode !== NoxRepeatMode.REPEAT_TRACK) {
logger.debug(
`[FADEOUT] fading out....${event.position} / ${event.duration}`
);
TrackPlayer.setAnimatedVolume({
volume: 0,
duration: fadeIntervalMs,
});
}
}
if (abRepeat[1] === 1) return;
if (event.position > bRepeatDuration) {
performSkipToNext();
}
});

useTrackPlayerEvents([Event.PlaybackState], async event => {
console.log('Event.PlaybackState', event);
if (event.state === State.Playing) {
fadePlay();
}
if (event.state !== State.Ready) return;
const song = (await TrackPlayer.getActiveTrack())?.song as NoxMedia.Song;
setABRepeat(getABRepeatRaw(song.id));
if (setCurrentPlaying(song)) return;
const trackDuration = (await TrackPlayer.getProgress()).duration;
setBRepeatDuration(abRepeat[1] * trackDuration);
if (abRepeat[0] === 0) return;
TrackPlayer.seekTo(trackDuration * abRepeat[0]);
});

return {
performSkipToNext,
performSkipToPrevious,
Expand Down
4 changes: 2 additions & 2 deletions src/components/playlist/PlaylistList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const PlaylistList = () => {
const [searchText, setSearchText] = useState('');
const [debouncedSearchText] = useDebounce(searchText, 500);
const [refreshing, setRefreshing] = useState(false);
const playlistRef = useRef<FlashList<NoxMedia.Song> | null>(null);
const playlistRef = useRef<FlashList<NoxMedia.Song>>(null);
const netInfo = useNetInfo();
// TODO: slow?
const [cachedSongs, setCachedSongs] = useState<string[]>([]);
Expand Down Expand Up @@ -364,7 +364,7 @@ const PlaylistList = () => {
</View>
<View style={stylesLocal.playlistContainer}>
<FlashList
ref={ref => (playlistRef.current = ref)}
ref={playlistRef}
data={currentRows}
renderItem={({ item, index }) => (
<SongBackground
Expand Down
Loading
Loading