Compare commits

...

2 Commits

Author SHA1 Message Date
Lei Nelissen
8e0809bcdc chore: Release v1.2.7 2022-08-14 00:49:48 +02:00
Lei Nelissen
5b54760e4e feat: Allow FLAC playback 2022-08-14 00:30:20 +02:00
10 changed files with 64 additions and 20 deletions

View File

@@ -138,8 +138,8 @@ android {
applicationId "com.jellyfinaudioplayer"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 10
versionName "1.2.6"
versionCode 11
versionName "1.2.7"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
if (isNewArchitectureEnabled()) {

View File

@@ -555,7 +555,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 38;
CURRENT_PROJECT_VERSION = 39;
DEVELOPMENT_TEAM = 238P3C58WC;
ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
@@ -591,7 +591,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 38;
CURRENT_PROJECT_VERSION = 39;
DEVELOPMENT_TEAM = 238P3C58WC;
INFOPLIST_FILE = JellyfinAudioPlayer/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";

View File

@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.6</string>
<string>1.2.7</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>38</string>
<string>39</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>

View File

@@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.6</string>
<string>1.2.7</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>38</string>
<string>39</string>
</dict>
</plist>

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "JellyfinAudioPlayer",
"version": "1.2.6",
"version": "1.2.7",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "JellyfinAudioPlayer",
"version": "1.2.6",
"version": "1.2.7",
"dependencies": {
"@react-native-async-storage/async-storage": "^1.17.6",
"@react-native-community/blur": "^3.6.0",

View File

@@ -1,6 +1,6 @@
{
"name": "JellyfinAudioPlayer",
"version": "1.2.6",
"version": "1.2.7",
"main": "src/index.js",
"private": true,
"scripts": {

View File

@@ -1,15 +1,16 @@
import { createAction, createAsyncThunk, createEntityAdapter, EntityId } from '@reduxjs/toolkit';
import { AppState } from 'store';
import { generateTrackUrl } from 'utility/JellyfinApi';
import { downloadFile, unlink, DocumentDirectoryPath } from 'react-native-fs';
import { downloadFile, unlink, DocumentDirectoryPath, exists } from 'react-native-fs';
import { DownloadEntity } from './types';
import MimeTypes from 'utility/MimeTypes';
export const downloadAdapter = createEntityAdapter<DownloadEntity>({
selectId: (entity) => entity.id,
});
export const queueTrackForDownload = createAction<EntityId>('download/queue');
export const initializeDownload = createAction<{ id: EntityId, size?: number, jobId?: number }>('download/initialize');
export const initializeDownload = createAction<{ id: EntityId, size?: number, jobId?: number, location: string }>('download/initialize');
export const progressDownload = createAction<{ id: EntityId, progress: number, jobId?: number }>('download/progress');
export const completeDownload = createAction<{ id: EntityId, location: string, size?: number }>('download/complete');
export const failDownload = createAction<{ id: EntityId }>('download/fail');
@@ -22,7 +23,21 @@ export const downloadTrack = createAsyncThunk(
// Generate the URL we can use to download the file
const url = generateTrackUrl(id as string, credentials);
const location = `${DocumentDirectoryPath}/${id}.mp3`;
// Get the content-type from the URL by doing a HEAD-only request
const contentType = (await fetch(url, { method: 'HEAD' })).headers.get('Content-Type');
if (!contentType) {
throw new Error('Jellyfin did not return a Content-Type for a streaming URL.');
}
// Then convert the MIME-type to an extension
const extension = MimeTypes[contentType as keyof typeof MimeTypes];
if (!extension) {
throw new Error('Jellyfin returned an unrecognized MIME-type');
}
// Then generate the proper location
const location = `${DocumentDirectoryPath}/${id}${extension}`;
// Actually kick off the download
const { promise } = await downloadFile({
@@ -31,7 +46,7 @@ export const downloadTrack = createAsyncThunk(
background: true,
begin: ({ jobId, contentLength }) => {
// Dispatch the initialization
dispatch(initializeDownload({ id, jobId, size: contentLength }));
dispatch(initializeDownload({ id, jobId, size: contentLength, location }));
},
progress: (result) => {
// Dispatch a progress update
@@ -48,8 +63,20 @@ export const downloadTrack = createAsyncThunk(
export const removeDownloadedTrack = createAsyncThunk(
'/downloads/remove/track',
async(id: EntityId) => {
return unlink(`${DocumentDirectoryPath}/${id}.mp3`);
async(id: EntityId, { getState }) => {
// Retrieve the state
const { downloads: { entities }} = getState() as AppState;
// Attempt to retrieve the entity from the state
const download = entities[id];
if (!download) {
throw new Error('Attempted to remove unknown downloaded track.');
}
// Then unlink the file, if it exists
if (await exists(download.location)) {
return unlink(download.location);
}
}
);

View File

@@ -6,6 +6,6 @@ export interface DownloadEntity {
isFailed: boolean;
isComplete: boolean;
size?: number;
location?: string;
location: string;
jobId?: number;
}

View File

@@ -22,8 +22,7 @@ const baseTrackOptions: Record<string, string> = {
// This must be set to support client seeking
TranscodingProtocol: 'http',
TranscodingContainer: 'aac',
Container: 'mp3,aac,m4a,m4b|aac,alac,m4a,m4b|alac,flac|ogg',
AudioCodec: 'aac',
Container: 'mp3,aac,m4a,m4b|aac,flac,alac,m4a,m4b|alac,flac|ogg',
static: 'true',
};

18
src/utility/MimeTypes.ts Normal file
View File

@@ -0,0 +1,18 @@
/**
* The filetypes this application will most probably receive.
* Adapted from: https://github.com/jellyfin/jellyfin/blob/63d943aab92a4b5f69e625a269eb830bcbfb4d22/MediaBrowser.Model/Net/MimeTypes.cs#L107
*/
const MimeTypes = {
'audio/aac': '.aac',
'audio/ac3': '.ac3',
'audio/dsf': '.dsf',
'audio/dsp': '.dsp',
'audio/flac': '.flac',
'audio/m4b': '.m4b',
'audio/vorbis': '.vorbis',
'audio/x-ape': '.ape',
'audio/xsp': '.xsp',
'audio/x-wavpack': '.wv',
};
export default MimeTypes;