Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fc0b0dddac | ||
![]() |
26c032c6fb | ||
![]() |
2179b63abe | ||
![]() |
d23fd85cdd | ||
![]() |
86a6501e86 | ||
![]() |
d1e1cc0ce5 | ||
![]() |
ed27109a51 | ||
![]() |
37dea6c47a | ||
![]() |
3947d1d6a6 | ||
![]() |
c606f6a701 | ||
![]() |
62951d0b80 |
17 changed files with 6073 additions and 22 deletions
4
.expo-shared/assets.json
Executable file
4
.expo-shared/assets.json
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"f9155ac790fd02fadcdeca367b02581c04a353aa6d5aa84409a59f6804c87acd": true,
|
||||||
|
"89ed26367cdb9b771858e026f2eb95bfdb90e5ae943e716575327ec325f39c44": true
|
||||||
|
}
|
18
.gitignore
vendored
Executable file
18
.gitignore
vendored
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
node_modules/**/*
|
||||||
|
.expo/*
|
||||||
|
npm-debug.*
|
||||||
|
*.jks
|
||||||
|
*.p8
|
||||||
|
*.p12
|
||||||
|
*.key
|
||||||
|
*.mobileprovision
|
||||||
|
*.orig.*
|
||||||
|
web-build/
|
||||||
|
web-report/
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# more stuff
|
||||||
|
*.bash
|
||||||
|
|
40
App.js
Normal file
40
App.js
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
// Nav stuff
|
||||||
|
|
||||||
|
//import { createAppContainer } from 'react-navigation';
|
||||||
|
//import { createStackNavigator } from 'react-navigation-stack';
|
||||||
|
|
||||||
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
|
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||||
|
|
||||||
|
// Screens one per file to keep things clean
|
||||||
|
|
||||||
|
import HomeScreen from './src/screens/HomeScreen';
|
||||||
|
import AboutScreen from './src/screens/AboutScreen';
|
||||||
|
import SettingsScreen from './src/screens/SettingsScreen';
|
||||||
|
import FilesScreen from './src/screens/FilesScreen';
|
||||||
|
|
||||||
|
// Clean up of code before I fix the last little issue with it
|
||||||
|
|
||||||
|
|
||||||
|
const Stack = createNativeStackNavigator();
|
||||||
|
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<NavigationContainer>
|
||||||
|
<Stack.Navigator initialRouteName="Home">
|
||||||
|
<Stack.Screen name="Home" component={HomeScreen} />
|
||||||
|
<Stack.Screen name="About" component={AboutScreen} />
|
||||||
|
<Stack.Screen name="Files" component={FilesScreen} />
|
||||||
|
<Stack.Screen name="Settings" component={SettingsScreen} />
|
||||||
|
|
||||||
|
</Stack.Navigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//export default createAppContainer(AppNavigator);
|
||||||
|
|
||||||
|
export default App;
|
5
LICENSE
5
LICENSE
|
@ -631,9 +631,8 @@ to attach them to the start of each source file to most effectively
|
||||||
state the exclusion of warranty; and each file should have at least
|
state the exclusion of warranty; and each file should have at least
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
Raspberry Pi Media center
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
Copyright (C) 2020 Paul Malcher
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|
19
README.md
19
README.md
|
@ -1,21 +1,2 @@
|
||||||
# rpimc
|
# rpimc
|
||||||
Raspberry PI Medial Center
|
Raspberry PI Medial Center
|
||||||
|
|
||||||
Designed to be used with a google chromecasts. Componets seperated into branches.
|
|
||||||
|
|
||||||
# Current Status as of 1/10/22
|
|
||||||
|
|
||||||
Allot of recent work on the Frontend. A large part due to having to update the code to a newer version of expo. Backend is ok for the most part a few items to do. See issues for a break down.
|
|
||||||
|
|
||||||
# Frontend Branch
|
|
||||||
A react native android application, acts as a remote control. This is built using
|
|
||||||
Expo.
|
|
||||||
|
|
||||||
# Backend Branch
|
|
||||||
A Python based web service and controller chromecasts
|
|
||||||
|
|
||||||
# Notes
|
|
||||||
Example for cloning the frontend
|
|
||||||
git clone -b frontend https://github.com/kake26/rpimc.git
|
|
||||||
|
|
||||||
Some values still hardcoded as its a work in progress. 1.0 Release will be soon.
|
|
||||||
|
|
32
app.json
Normal file
32
app.json
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "csrv",
|
||||||
|
"slug": "csrv",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"orientation": "portrait",
|
||||||
|
"icon": "./assets/icon.png",
|
||||||
|
"splash": {
|
||||||
|
"image": "./assets/splash.png",
|
||||||
|
"resizeMode": "contain",
|
||||||
|
"backgroundColor": "#ffffff"
|
||||||
|
},
|
||||||
|
"updates": {
|
||||||
|
"fallbackToCacheTimeout": 0
|
||||||
|
},
|
||||||
|
"assetBundlePatterns": [
|
||||||
|
"**/*"
|
||||||
|
],
|
||||||
|
"ios": {
|
||||||
|
"supportsTablet": true
|
||||||
|
},
|
||||||
|
"android": {
|
||||||
|
"adaptiveIcon": {
|
||||||
|
"foregroundImage": "./assets/adaptive-icon.png",
|
||||||
|
"backgroundColor": "#FFFFFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"web": {
|
||||||
|
"favicon": "./assets/favicon.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
assets/adaptive-icon.png
Normal file
BIN
assets/adaptive-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
assets/favicon.png
Normal file
BIN
assets/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/icon.png
Normal file
BIN
assets/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
assets/splash.png
Normal file
BIN
assets/splash.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
6
babel.config.js
Normal file
6
babel.config.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = function(api) {
|
||||||
|
api.cache(true);
|
||||||
|
return {
|
||||||
|
presets: ['babel-preset-expo'],
|
||||||
|
};
|
||||||
|
};
|
32
package.json
Normal file
32
package.json
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name": "csrv",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "node_modules/expo/AppEntry.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start",
|
||||||
|
"android": "expo start --android",
|
||||||
|
"ios": "expo start --ios",
|
||||||
|
"web": "expo start --web",
|
||||||
|
"eject": "expo eject"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@react-native-async-storage/async-storage": "~1.15.0",
|
||||||
|
"@react-navigation/native": "^6.0.6",
|
||||||
|
"@react-navigation/native-stack": "^6.2.5",
|
||||||
|
"axios": "^0.24.0",
|
||||||
|
"expo": "^44.0.3",
|
||||||
|
"expo-status-bar": "~1.2.0",
|
||||||
|
"react": "17.0.1",
|
||||||
|
"react-dom": "17.0.1",
|
||||||
|
"react-native": "0.64.3",
|
||||||
|
"react-native-elements": "^3.4.2",
|
||||||
|
"react-native-safe-area-context": "3.3.2",
|
||||||
|
"react-native-screen": "^1.0.1",
|
||||||
|
"react-native-screens": "~3.10.1",
|
||||||
|
"react-native-web": "0.17.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.12.9"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
29
src/screens/AboutScreen.js
Executable file
29
src/screens/AboutScreen.js
Executable file
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
const AboutScreen = ({ navigation }) => {
|
||||||
|
|
||||||
|
const navigationOptions = ({ navigation }) => {
|
||||||
|
return {
|
||||||
|
title: navigation.getParam('otherParam', 'About'),
|
||||||
|
headerStyle: {
|
||||||
|
backgroundColor: '#3333ff',
|
||||||
|
},
|
||||||
|
headerTintColor: '#fff',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||||
|
<Text>About Screen{"\n"}{"\n"}
|
||||||
|
RPI Media Center Control v 1.0 beta</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default AboutScreen;
|
72
src/screens/FilesScreen.js
Executable file
72
src/screens/FilesScreen.js
Executable file
|
@ -0,0 +1,72 @@
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
FlatList, // Solves the problem with the 5 movie limit in the app
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
// these imports make headers and buttons look better
|
||||||
|
import {
|
||||||
|
Header,
|
||||||
|
Button,
|
||||||
|
} from 'react-native-elements';
|
||||||
|
|
||||||
|
function play(name) {
|
||||||
|
// Play handler
|
||||||
|
axios.get('http://192.168.1.178:8080/play/'+name)
|
||||||
|
.then(res => {
|
||||||
|
// Still don't care about response
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const FilesScreen = ({ navigation }) => {
|
||||||
|
|
||||||
|
const [movies, setValue] = useState(null);
|
||||||
|
|
||||||
|
const baseURL = "http://192.168.1.178:8080";
|
||||||
|
|
||||||
|
const navigationOptions = ({ navigation }) => {
|
||||||
|
return {
|
||||||
|
title: navigation.getParam('otherParam', 'File Selection'),
|
||||||
|
headerStyle: {
|
||||||
|
backgroundColor: '#3333ff',
|
||||||
|
},
|
||||||
|
headerTintColor: '#fff',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
axios.get(`${baseURL}/list/`).then((response) => {
|
||||||
|
setValue(response.data.data);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
if (!movies) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
|
||||||
|
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||||
|
<Text>Pick a movie</Text>
|
||||||
|
<FlatList
|
||||||
|
keyExtractor={movies => movies}
|
||||||
|
data={movies}
|
||||||
|
renderItem={({ item }) => {
|
||||||
|
return <Button title={item} type="outline" onPress = {() => play(item)}
|
||||||
|
/>
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default FilesScreen;
|
93
src/screens/HomeScreen.js
Executable file
93
src/screens/HomeScreen.js
Executable file
|
@ -0,0 +1,93 @@
|
||||||
|
//import React from 'react';
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { useAsyncStorage } from '@react-native-async-storage/async-storage';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
} from 'react-native-elements';
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
} from 'react-native';
|
||||||
|
// play,pause,stop icons
|
||||||
|
import { AntDesign } from '@expo/vector-icons';
|
||||||
|
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||||
|
import axios from 'axios'; // Took a while to figure out how to use it, but its simpler then the
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const HomeScreen = ({ navigation }) => {
|
||||||
|
|
||||||
|
const navigationOptions = ({ navigation }) => {
|
||||||
|
return {
|
||||||
|
title: navigation.getParam('otherParam', 'RPI Media Center Control'),
|
||||||
|
headerStyle: {
|
||||||
|
backgroundColor: '#3333ff',
|
||||||
|
},
|
||||||
|
headerTintColor: '#fff',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function bp (name) {
|
||||||
|
// Button press handler important
|
||||||
|
axios.get('http://192.168.1.178:8080/'+name)
|
||||||
|
.then(res => {
|
||||||
|
// We don't care fore now
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const [value, setValue] = useState('value');
|
||||||
|
const { getItem, setItem } = useAsyncStorage('@storage_key');
|
||||||
|
|
||||||
|
const readItemFromStorage = async () => {
|
||||||
|
const item = await getItem();
|
||||||
|
setValue(item);
|
||||||
|
};
|
||||||
|
|
||||||
|
const writeItemToStorage = async newValue => {
|
||||||
|
await setItem(newValue);
|
||||||
|
setValue(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
readItemFromStorage();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center'}}>
|
||||||
|
<Text>Server IP: {value}</Text>
|
||||||
|
<Text>Controls</Text>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
title="Select file to play" type="outline"
|
||||||
|
onPress={() => navigation.navigate('Files')} //navigationOptions.navigate('Files')}
|
||||||
|
/><Text>{"\n"}</Text>
|
||||||
|
|
||||||
|
<View style={{flexDirection: 'row' }}>
|
||||||
|
<Button
|
||||||
|
icon={<AntDesign name="pausecircleo" size={24} color="black" />} title="Pause" type="outline"
|
||||||
|
onPress = {() => bp('pause/')}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon={<AntDesign name="playcircleo" size={24} color="black" />} title="Resume" type="outline"
|
||||||
|
onPress = {() => bp('resume/')}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon={<MaterialCommunityIcons name="stop-circle-outline" size={24} color="black" />} title="Stop" type="outline"
|
||||||
|
onPress = {() => bp('stop/')}
|
||||||
|
/><Text>{"\n"}</Text>
|
||||||
|
</View>
|
||||||
|
<Text>{"\n"}</Text>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
title="Settings" type="outline"
|
||||||
|
onPress={() => navigation.navigate('Settings')}
|
||||||
|
/><Text>{"\n"}</Text>
|
||||||
|
<Button
|
||||||
|
title="About" type="outline"
|
||||||
|
onPress={() => navigation.navigate('About')}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HomeScreen;
|
47
src/screens/SettingsScreen.js
Executable file
47
src/screens/SettingsScreen.js
Executable file
|
@ -0,0 +1,47 @@
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Header,
|
||||||
|
Button,
|
||||||
|
} from 'react-native-elements';
|
||||||
|
|
||||||
|
import { useAsyncStorage } from '@react-native-async-storage/async-storage';
|
||||||
|
|
||||||
|
// I know all the previous stuff uses componets and classes, but for now this is the
|
||||||
|
// Only way I can get this to work properly
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
const [value, setValue] = useState('value');
|
||||||
|
const { getItem, setItem } = useAsyncStorage('@storage_key');
|
||||||
|
|
||||||
|
const readItemFromStorage = async () => {
|
||||||
|
const item = await getItem();
|
||||||
|
setValue(item);
|
||||||
|
};
|
||||||
|
|
||||||
|
const writeItemToStorage = async newValue => {
|
||||||
|
await setItem(newValue);
|
||||||
|
setValue(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
readItemFromStorage();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center'}}>
|
||||||
|
<Text>Server IP: {value}</Text>
|
||||||
|
<Text>{"\n"}</Text>
|
||||||
|
<TextInput onChangeText={newValue => writeItemToStorage(newValue) } style={{borderWidth: 1, width: 100}}>{value}</TextInput>
|
||||||
|
|
||||||
|
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue