mirror of
https://github.com/jellyfin/jellyfin-expo.git
synced 2024-12-04 04:01:42 +00:00
Report playback stopped when download finishes
This commit is contained in:
parent
c2408ec37c
commit
edb7fc6087
23
App.js
23
App.js
@ -8,6 +8,7 @@
|
|||||||
import 'react-native-url-polyfill/auto';
|
import 'react-native-url-polyfill/auto';
|
||||||
|
|
||||||
import { Ionicons } from '@expo/vector-icons';
|
import { Ionicons } from '@expo/vector-icons';
|
||||||
|
import { getPlaystateApi } from '@jellyfin/sdk/lib/utils/api/playstate-api';
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
import { NavigationContainer } from '@react-navigation/native';
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
import { Asset } from 'expo-asset';
|
import { Asset } from 'expo-asset';
|
||||||
@ -20,7 +21,7 @@ import { observer } from 'mobx-react-lite';
|
|||||||
import { AsyncTrunk } from 'mobx-sync-lite';
|
import { AsyncTrunk } from 'mobx-sync-lite';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { useColorScheme } from 'react-native';
|
import { Alert, useColorScheme } from 'react-native';
|
||||||
import { ThemeContext, ThemeProvider } from 'react-native-elements';
|
import { ThemeContext, ThemeProvider } from 'react-native-elements';
|
||||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
@ -140,7 +141,27 @@ const App = observer(({ skipLoadingScreen }) => {
|
|||||||
download.isDownloading = false;
|
download.isDownloading = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[App] Download failed', e);
|
console.error('[App] Download failed', e);
|
||||||
|
Alert.alert('Download Failed', `"${download.title}" failed to download.`);
|
||||||
|
|
||||||
|
// TODO: If a download fails, we should probably remove it from the queue
|
||||||
download.isDownloading = false;
|
download.isDownloading = false;
|
||||||
|
} finally {
|
||||||
|
const serverUrl = download.serverUrl.endsWith('/') ? download.serverUrl.slice(0, -1) : download.serverUrl;
|
||||||
|
const api = rootStore.sdk.createApi(serverUrl);
|
||||||
|
console.log('[App] Reporting download stopped', download.sessionId);
|
||||||
|
getPlaystateApi(api)
|
||||||
|
.reportPlaybackStopped({
|
||||||
|
playbackStopInfo: {
|
||||||
|
PlaySessionId: download.sessionId
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
query: {
|
||||||
|
api_key: download.apiKey
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error('[App] Failed reporting download stopped', err.response || err.request || err.message);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
import * as FileSystem from 'expo-file-system';
|
import * as FileSystem from 'expo-file-system';
|
||||||
import { computed, decorate, observable } from 'mobx';
|
import { computed, decorate, observable } from 'mobx';
|
||||||
import { ignore } from 'mobx-sync-lite';
|
import { ignore } from 'mobx-sync-lite';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
export default class DownloadModel {
|
export default class DownloadModel {
|
||||||
isComplete = false
|
isComplete = false
|
||||||
@ -15,6 +16,8 @@ export default class DownloadModel {
|
|||||||
|
|
||||||
apiKey: string
|
apiKey: string
|
||||||
itemId: string
|
itemId: string
|
||||||
|
/** The "play" session ID for reporting a download has stopped. */
|
||||||
|
sessionId = uuidv4()
|
||||||
serverId: string
|
serverId: string
|
||||||
serverUrl: string
|
serverUrl: string
|
||||||
|
|
||||||
@ -61,6 +64,7 @@ export default class DownloadModel {
|
|||||||
const streamParams = new URLSearchParams({
|
const streamParams = new URLSearchParams({
|
||||||
deviceId,
|
deviceId,
|
||||||
api_key: this.apiKey,
|
api_key: this.apiKey,
|
||||||
|
playSessionId: this.sessionId,
|
||||||
// TODO: add mediaSourceId to support alternate media versions
|
// TODO: add mediaSourceId to support alternate media versions
|
||||||
videoCodec: 'hevc,h264',
|
videoCodec: 'hevc,h264',
|
||||||
audioCodec: 'aac,mp3,ac3,eac3,flac,alac',
|
audioCodec: 'aac,mp3,ac3,eac3,flac,alac',
|
||||||
@ -79,6 +83,7 @@ decorate(DownloadModel, {
|
|||||||
isNew: observable,
|
isNew: observable,
|
||||||
apiKey: observable,
|
apiKey: observable,
|
||||||
itemId: observable,
|
itemId: observable,
|
||||||
|
sessionId: observable,
|
||||||
serverId: observable,
|
serverId: observable,
|
||||||
serverUrl: observable,
|
serverUrl: observable,
|
||||||
title: observable,
|
title: observable,
|
||||||
|
44
package-lock.json
generated
44
package-lock.json
generated
@ -2126,6 +2126,41 @@
|
|||||||
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
|
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@jellyfin/sdk": {
|
||||||
|
"version": "0.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.7.0.tgz",
|
||||||
|
"integrity": "sha512-GNoGv+2qY+xK7WpO7sUUNpZvzgN7RwXMyOhIy9mE/LdDSr6bqZHwrzT1Pv0+vUW7Epw67bwIMWuYivyBYejEHw==",
|
||||||
|
"requires": {
|
||||||
|
"axios": "0.27.2",
|
||||||
|
"compare-versions": "5.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": {
|
||||||
|
"version": "0.27.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||||
|
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||||
|
"requires": {
|
||||||
|
"follow-redirects": "^1.14.9",
|
||||||
|
"form-data": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compare-versions": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-v8Au3l0b+Nwkp4G142JcgJFh1/TUhdxut7wzD1Nq1dyp5oa3tXaqb03EXOAB6jS4gMlalkjAUPZBMiAfKUixHQ=="
|
||||||
|
},
|
||||||
|
"form-data": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
|
"requires": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@jest/console": {
|
"@jest/console": {
|
||||||
"version": "26.6.2",
|
"version": "26.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz",
|
||||||
@ -3694,6 +3729,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/uuid": {
|
||||||
|
"version": "8.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
|
||||||
|
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/webpack": {
|
"@types/webpack": {
|
||||||
"version": "4.41.33",
|
"version": "4.41.33",
|
||||||
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.33.tgz",
|
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.33.tgz",
|
||||||
@ -9320,8 +9361,7 @@
|
|||||||
"follow-redirects": {
|
"follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"fontfaceobserver": {
|
"fontfaceobserver": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
"Android >= 5"
|
"Android >= 5"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@jellyfin/sdk": "^0.7.0",
|
||||||
"@react-native-async-storage/async-storage": "~1.17.3",
|
"@react-native-async-storage/async-storage": "~1.17.3",
|
||||||
"@react-native-community/masked-view": "0.1.10",
|
"@react-native-community/masked-view": "0.1.10",
|
||||||
"@react-navigation/bottom-tabs": "^6.0.7",
|
"@react-navigation/bottom-tabs": "^6.0.7",
|
||||||
@ -82,6 +83,7 @@
|
|||||||
"@testing-library/react-native": "^7.2.0",
|
"@testing-library/react-native": "^7.2.0",
|
||||||
"@types/jest": "^27.0.2",
|
"@types/jest": "^27.0.2",
|
||||||
"@types/react": "~17.0.21",
|
"@types/react": "~17.0.21",
|
||||||
|
"@types/uuid": "^8.3.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
||||||
"@typescript-eslint/parser": "^4.33.0",
|
"@typescript-eslint/parser": "^4.33.0",
|
||||||
"babel-preset-expo": "~9.1.0",
|
"babel-preset-expo": "~9.1.0",
|
||||||
|
@ -7,10 +7,14 @@
|
|||||||
// polyfill crypto.getRandomValues
|
// polyfill crypto.getRandomValues
|
||||||
import 'react-native-get-random-values';
|
import 'react-native-get-random-values';
|
||||||
|
|
||||||
import { action, decorate, observable } from 'mobx';
|
import { Jellyfin } from '@jellyfin/sdk';
|
||||||
|
import Constants from 'expo-constants';
|
||||||
|
import { action, computed, decorate, observable } from 'mobx';
|
||||||
import { ignore } from 'mobx-sync-lite';
|
import { ignore } from 'mobx-sync-lite';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
import { getAppName, getSafeDeviceName } from '../utils/Device';
|
||||||
|
|
||||||
import DownloadStore from './DownloadStore';
|
import DownloadStore from './DownloadStore';
|
||||||
import MediaStore from './MediaStore';
|
import MediaStore from './MediaStore';
|
||||||
import ServerStore from './ServerStore';
|
import ServerStore from './ServerStore';
|
||||||
@ -47,6 +51,19 @@ export default class RootStore {
|
|||||||
serverStore = new ServerStore()
|
serverStore = new ServerStore()
|
||||||
settingStore = new SettingStore()
|
settingStore = new SettingStore()
|
||||||
|
|
||||||
|
get sdk() {
|
||||||
|
return (new Jellyfin({
|
||||||
|
clientInfo: {
|
||||||
|
name: getAppName(),
|
||||||
|
version: Constants.nativeAppVersion
|
||||||
|
},
|
||||||
|
deviceInfo: {
|
||||||
|
name: getSafeDeviceName(),
|
||||||
|
id: this.deviceId
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.deviceId = uuidv4();
|
this.deviceId = uuidv4();
|
||||||
|
|
||||||
@ -69,5 +86,6 @@ decorate(RootStore, {
|
|||||||
isFullscreen: [ ignore, observable ],
|
isFullscreen: [ ignore, observable ],
|
||||||
isReloadRequired: [ ignore, observable ],
|
isReloadRequired: [ ignore, observable ],
|
||||||
didPlayerCloseManually: [ ignore, observable ],
|
didPlayerCloseManually: [ ignore, observable ],
|
||||||
|
sdk: computed,
|
||||||
reset: action
|
reset: action
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user