This commit is contained in:
Alex 2022-03-19 00:59:01 +13:00
commit 0d3ddd916f
23 changed files with 202 additions and 94 deletions

View File

@ -110,4 +110,4 @@ jobs:
uses: actions/upload-artifact@v2
with:
name: iOS
path: ~/Library/Developer/Xcode/DerivedData
path: ~/Library/Developer/Xcode/DerivedData/App-*/Build/Products/Debug-iphoneos/App.app

View File

@ -31,6 +31,8 @@ export default {
<style scoped>
.bottomNav {
box-shadow: none !important;
height: 4rem !important;
position: fixed;
bottom: 0;
padding: 0 !important;

View File

@ -25,12 +25,13 @@ export default {
updateSnackbarTimeout: 5000
}
},
async mounted() {
const commits = await this.$vuetube.commits;
if (commits[0].sha != process.env.appVersion) {
const appVersion = process.env.appVersion;
if (appVersion !== commits[0].sha && appVersion !== 'dev-local') {
this.updateSnackbar = true;
}
},
}
</script>
</script>

View File

@ -1,6 +1,13 @@
<template>
<v-app>
<v-card class="topNav rounded-0" style="display: flex; box-shadow: none !important;" color="accent white--text">
<v-app style="background: black !important;">
<v-card
:style="{
borderRadius: roblox ? '0rem' : '1rem 1rem 0px 0px !important'
}"
style="height: 4rem !important; display: flex; box-shadow: none !important;"
color="accent white--text"
class="topNav rounded-0"
>
<h2 v-text="page" v-show="!search" />
<v-text-field
@ -14,33 +21,40 @@
<v-spacer />
<v-btn text class="toolbarAction mr-2 fill-height" color="white" @click="search = !search"><v-icon>mdi-magnify</v-icon></v-btn>
<v-btn text class="toolbarAction mr-2 fill-height" color="white" @click="searchBtn()"><v-icon>mdi-magnify</v-icon></v-btn>
<v-btn text class="toolbarAction fill-height" color="white" v-show="!search" to="/settings"><v-icon>mdi-dots-vertical</v-icon></v-btn>
</v-card>
<div class="accent" style="height: 100%">
<div class="background">
<div style="height: calc(100% - 1rem); margin-top: 1rem; padding-top: 3rem; background: linear-gradient(var(--v-accent-base) 0%, var(--v-accent2-base) 100%); border-radius: 1rem;">
<div
class="background scroll-y"
style="padding: 0; height: calc(100vh - 8rem); overflow-x: hidedn;"
:style="{
borderRadius: roblox ? '0rem' : '1rem'
}"
>
<nuxt v-show="!search" />
<div style="min-width: 180px;" v-if="search">
<v-list-item v-for="(item, index) in response" :key="index">
<v-btn text dense class="info--text searchButton text-left" @click="youtubeSearch(item)" v-text="item[0]" />
</v-list-item>
</div>
</div>
</div>
<bottomNavigation v-if="!search" />
<bottomNavigation v-if="!search"
:style="{
borderRadius: roblox ? '0rem' : '0 0 1rem 1rem !important'
}"
/>
<updateChecker />
</v-app>
</template>
@ -48,8 +62,13 @@
* {
font-family: Arial, Helvetica, sans-serif !important;
}
.scroll-y {
overflow-y: scroll !important; /* has to be scroll, not auto */
-webkit-overflow-scrolling: touch !important;
}
html, body {
overflow-x: hidden;
background: black;
overflow: hidden;
}
p, span, div {
@ -85,7 +104,7 @@ p, span, div {
margin: 0;
position: absolute;
transform: translateY(-10%);
width: 80%
width: 75%
}
.searchButton {
width: 100%;
@ -101,18 +120,24 @@ export default {
text: null,
response: [],
roblox: false,
}),
mounted() {
//--- Load Saved Radius ---//
setInterval(() => { // im sorry I'll fix this later
this.roblox = localStorage.getItem("roblox") == "true";
}, 1000);
//--- Load Saved Theme ---//
setTimeout(() => { //Set timeout is required to make it load properly... dont ask me why -Front
const darkTheme = localStorage.getItem('darkTheme');
if (darkTheme == "true") {
this.$vuetify.theme.dark = darkTheme;
this.$vuetube.statusBar.setDark();
const isOled = localStorage.getItem('isOled')
if(isOled == "true") {
this.$vuetify.theme.themes.dark.accent = '#000',
this.$vuetify.theme.themes.dark.accent2 = '#000',
@ -122,6 +147,8 @@ export default {
this.$vuetify.theme.themes.dark.accent2 = '#222',
this.$vuetify.theme.themes.dark.background = '#333'
}
} else {
this.$vuetube.statusBar.setLight()
}
}, 0);
@ -141,6 +168,10 @@ export default {
});
},
computed: {
// TODO: says localStorage is undefined, idk why 😭
// roblox () {
// return localStorage.getItem("roblox") === null ? false : localStorage.getItem("roblox")
// },
page: function () {
const splitPath = this.$route.path.split("/");
let pageName = splitPath[splitPath.length-1];
@ -160,7 +191,19 @@ export default {
youtubeSearch(item) {
this.$router.push(`/search?q=${item[0]}`);
this.search = false;
},
searchBtn() {
const query = this.text;
if (this.search === true) {
this.$router.push(`/search?q=${query}`);
this.search = false;
} else {
this.search = true;
}
}
}
}
</script>

View File

@ -16,8 +16,7 @@ export default {
target: 'static',
plugins: [
{ src: "~/plugins/youtube", mode: "client" },
{ src: "~/plugins/vuetube", mode: "client" },
{ src: "~/plugins/libs", mode: "client" }
{ src: "~/plugins/vuetube", mode: "client" }
],
generate: {
dir: '../dist'
@ -56,6 +55,7 @@ export default {
customVariables: ['~/assets/variables.scss'],
theme: {
dark: false,
options: { customProperties: true },
themes: {
light: {
primary: colors.red.lighten2,

View File

@ -1,6 +1,6 @@
<template>
<center>
<img style="margin-top: 5em; max-width: 80%; max-height: 15em;" src="/dev.svg" />
<v-img contain style="margin-top: 5em; max-width: 80%; max-height: 15em;" src="/dev.svg" />
<h1 class="grey--text">Page Under Construction</h1>
<p class="grey--text">Please read the VueTube FAQ for more information.</p>
</center>

View File

@ -1,11 +1,17 @@
<template>
<center style="padding: 1em;">
<v-img src="/icon.svg" width="100px" />
<h1 class="pageTitle">VueTube</h1>
<v-btn @click="openExternal('https://github.com/Frontesque/VueTube')"><v-icon>mdi-github</v-icon></v-btn>
<v-btn @click="openExternal('https://discord.gg/7P8KJrdd5W')"><v-icon>mdi-discord</v-icon></v-btn>
<div class="row pa-4">
<div>
<v-img src="/icon.svg" width="100px"/>
</div>
<v-spacer/>
<div>
<h1 class="pageTitle mb-3">VueTube</h1>
<v-btn @click="openExternal('https://github.com/Frontesque/VueTube')"><v-icon>mdi-github</v-icon></v-btn>
<v-btn @click="openExternal('https://discord.gg/7P8KJrdd5W')"><v-icon>mdi-discord</v-icon></v-btn>
</div>
</div>
<h3 style="margin-top: 2em;">App Information</h3>
<div>App Version: {{ version.substring(0, 7) }}</div>

View File

@ -1,5 +1,21 @@
<template>
<div class="mainContainer pt-1">
<div class="py-1">
<v-card class="pb-5">
<v-card-title>Rounded Corners</v-card-title>
<v-row class="ml-3 mr-6">
<section class="row">
<v-switch
v-model="roblox"
label="Roblox"
hint="If you want UI to look like Minecraft"
persistent-hint
inset
@click="saveRadius(roblox)"
/>
</section>
</v-row>
</v-card>
<v-card class="pb-5">
<v-card-title>Global Base Color</v-card-title>
@ -31,7 +47,7 @@
<v-alert color="primary" dense outlined type="warning">NOTE: This doesn't save after closing the app (yet)</v-alert>
<v-color-picker dot-size="5" hide-mode-switch mode="hexa" v-model="accentColor" />
</v-card-text>
</v-card>
@ -44,12 +60,14 @@ export default {
data() {
return {
accentColor: '#ffffff'
accentColor: '#ffffff',
roblox: false,
}
},
mounted() {
this.accentColor = this.$vuetify.theme.themes.dark.primary;
this.roblox = localStorage.getItem('roblox') === 'true';
},
methods: {
@ -71,17 +89,32 @@ export default {
// console.log(document.getElementsByClassName('v-application--wrap')[0].style)
// document.getElementsByClassName('v-application--wrap')[0].style.backgroundColor = "#000000 !important"
},
saveTheme(isDark) {
localStorage.setItem("darkTheme", isDark);
},
saveRadius(value) {
localStorage.setItem("roblox", value);
},
},
computed: {
// 😩
// roblox: {
// get () {
// return localStorage.getItem("roblox") === 'true'
// },
// set (value) {
// if(process.client) {
// localStorage.setItem("roblox", value)
// }
// }
// }
},
watch: {
accentColor: function (val, oldVal) {
this.$vuetify.theme.currentTheme.primary = val;
let primaryAlt = this.$libs.hexToRgb(val);
let primaryAlt = this.$vuetube.hexToRgb(val);
let rgbEdit = 130; //Light Mode
if (localStorage.getItem('darkTheme') === "true") rgbEdit = -80; //Dark Mode
@ -92,8 +125,8 @@ export default {
if (primaryAlt[i] < 0) primaryAlt[i] = 0;
}
primaryAlt = this.$libs.rgbToHex(primaryAlt.r, primaryAlt.g, primaryAlt.b);
primaryAlt = this.$vuetube.rgbToHex(primaryAlt.r, primaryAlt.g, primaryAlt.b);
this.$vuetify.theme.currentTheme.primaryAlt = primaryAlt;

View File

@ -1,13 +1,13 @@
<template>
<div>
<div class="py-2">
<v-list-item v-for="(item, index) in commits" :key="index">
<v-card class="card">
<v-list-item v-for="(item, index) in commits" :key="index" class="my-1">
<v-card class="card my-2">
<v-card-title style="padding: 0 0.25em 0 0.75em;">
{{ item.author ? item.author.login : item.commit.author.name }}
<span v-text="` ${item.sha.substring(0, 7)}`" class="subtitle" />
<v-spacer />
<v-chip outlined class="tags" color="orange" v-if="index == 0">Latest</v-chip>
<v-chip outlined class="tags" style="border-radius: 0 5px 0 5px; margin-top: -12px; margin-right: -5px;" color="orange" v-if="index == 0">Latest</v-chip>
<v-chip outlined class="tags" color="green" v-if="item.sha == installedVersion">Installed</v-chip>
</v-card-title>
@ -31,7 +31,6 @@
<style scoped>
.card {
width: 100%;
margin: 1em 0 1em 0;
}
.subtitle {
margin: 0.4em;

View File

@ -1,12 +1,9 @@
<template>
<div>
<div class="py-1">
<center style="padding-top: 3em;" v-if="videos == null">
<v-progress-circular
size="50"
indeterminate
color="primary"
/>
<center v-if="videos.length == 0">
<v-skeleton-loader type="card-avatar, article, actions" />
<v-skeleton-loader type="card-avatar, article, actions" />
</center>
<v-list-item v-for="(video, index) in videos" :key="index">
@ -43,14 +40,13 @@
export default {
data() {
return {
videos: null
videos: []
}
},
mounted() {
const searchQuestion = this.$route.query.q
const vm = this;
this.$youtube.search(searchQuestion, (data) => {
console.log(data)
vm.videos = data;
})
}

View File

@ -1,6 +1,6 @@
<template>
<center>
<img style="margin-top: 5em; max-width: 80%; max-height: 15em;" src="/dev.svg" />
<v-img contain style="margin-top: 5em; max-width: 80%; max-height: 15em;" src="/dev.svg" />
<h1 class="grey--text">Page Under Construction</h1>
<p class="grey--text">Please read the VueTube FAQ for more information.</p>
</center>

View File

@ -13,9 +13,8 @@ export default {
}
},
mounted() {
this.$youtube.getVideo('wykQsTJElD4', (data) => {
this.vidSrc = data;
})
const { v } = this.$route.query
console.log(v, this.$youtube.getVid(v))
}
}
</script>

View File

@ -1,22 +0,0 @@
const module = {
hexToRgb: function (hex, callback) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
},
rgbToHex: function(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
}
//--- Start ---//
export default ({ app }, inject) => {
inject('libs', module)
}

View File

@ -1,13 +1,28 @@
// Collection of functions that are useful but non-specific to any particular files
// Collection of functions that are useful but non-specific to any particular files
function getBetweenStrings(data, start_string, end_string) {
const regex = new RegExp(`${escapeRegExp(start_string)}(.*?)${escapeRegExp(end_string)}`, "s");
const match = data.match(regex);
return match ? match[1] : undefined;
const regex = new RegExp(`${escapeRegExp(start_string)}(.*?)${escapeRegExp(end_string)}`, "s");
const match = data.match(regex);
return match ? match[1] : undefined;
}
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
module.exports = { getBetweenStrings };
function hexToRgb(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
module.exports = { getBetweenStrings, hexToRgb, rgbToHex };

View File

@ -1,6 +1,8 @@
//--- Modules/Imports ---//
import { Http } from '@capacitor-community/http';
import { StatusBar, Style } from '@capacitor/status-bar';
import constants from '../static/constants';
import { hexToRgb, rgbToHex } from './utils';
const module = {
@ -37,11 +39,35 @@ const module = {
callback(err)
});
}
},
statusBar: {
async hide() {
return await StatusBar.hide();
},
async show() {
return await StatusBar.show();
},
async setLight() {
return await StatusBar.setStyle({ style: Style.Light });
},
async setDark() {
return await StatusBar.setStyle({ style: Style.Dark });
},
async setTransparent() {
return StatusBar.setOverlaysWebView({ overlay: true });
},
async setBackground(color) {
return await setBackgroundColor({color: color});
}
},
hexToRgb(hex) { return hexToRgb(hex); },
rgbToHex(r, g, b) { return rgbToHex(r, g, b); }
}
//--- Start ---//
export default ({ app }, inject) => {
inject('vuetube', module)
}
}

View File

@ -8,5 +8,5 @@
</option>
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK" />
</project>

View File

@ -18,7 +18,10 @@ If you wish to test the app within your browser, you can enter the `NUXT` direct
> NOTE2: If you get an error about `EACCES: permission denied 0.0.0.0:80`, change the port in `nuxt.config.js` back to 3000.
If you're done with your changes and are ready to submit your code, there is one last step: compiling to your android device. Plug in your Android or iOS device. Then, in the root directory of the project, run `npx cap run android` to test on your Android device or `npx cap run ios` to test on your iPhone. The app will proceed to build and you will be asked what device to install the debug application on. Select your device and wait as it compiles for you! Hopefully everything goes smoothly, and you are ready to make your pull request!
If you're done with your changes and are ready to submit your code, there is one last step: compiling to your android device.
- Plug in your Android or iOS device. (and make sure that ADB works for android by running `adb devices` in your ADB directory)
- Then, in the root directory of the project, run `./scripts/build.ps1` on windows or `./scripts/build.sh` for linux or mac.
- Finally, run `npx cap run android` to push to your android device or `npx cap run ios` for your ios device!
# Making a Pull Request
A pull request is fairly simple, and it's done here on GitHub. All we ask is that you include a few screenshots (and/or screen recordings) of what you've actually changed within the app.

View File

@ -346,11 +346,12 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = VRCJ7YWR89;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = com.Frontesque.youtube;
PRODUCT_BUNDLE_IDENTIFIER = com.Frontesque.vuetube;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_VERSION = 5.0;
@ -364,10 +365,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = VRCJ7YWR89;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.Frontesque.youtube;
PRODUCT_BUNDLE_IDENTIFIER = com.Frontesque.vuetube;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
SWIFT_VERSION = 5.0;

View File

@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>VueTube</string>
<string>VueTube</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>

View File

@ -9,10 +9,10 @@ install! 'cocoapods', :disable_input_output_paths => true
def capacitor_pods
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCommunityHttp', :path => '..\..\node_modules\@capacitor-community\http'
pod 'CapacitorApp', :path => '..\..\node_modules\@capacitor\app'
pod 'CapacitorBrowser', :path => '..\..\node_modules\@capacitor\browser'
pod 'CapacitorDevice', :path => '..\..\node_modules\@capacitor\device'
pod 'CapacitorCommunityHttp', :path => '../../node_modules/@capacitor-community/http'
pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
pod 'CapacitorBrowser', :path => '../../node_modules/@capacitor/browser'
pod 'CapacitorDevice', :path => '../../node_modules/@capacitor/device'
end
target 'App' do

View File

@ -6,6 +6,7 @@
"@capacitor/browser": "^1.0.7",
"@capacitor/cli": "^3.4.0",
"@capacitor/core": "^3.4.0",
"@capacitor/device": "^1.1.2"
"@capacitor/device": "^1.1.2",
"@capacitor/status-bar": "^1.0.8"
}
}

View File

@ -1,10 +1,14 @@
[![Discord](https://img.shields.io/discord/946587366242533377?label=Discord&style=flat&logo=discord)](https://discord.gg/7P8KJrdd5W)
# VueTube
<img src="https://github.com/Frontesque/VueTube/raw/main/Icons/VueTube.png" alt="VueTube icon" width="200"/>
A simple FOSS video streaming client aimed to recreate ALL features from their respective apps (and more)
- Pronounced View Tube
## Links
- Discord: [![Discord](https://img.shields.io/discord/946587366242533377?label=Discord&style=flat&logo=discord)](https://discord.gg/7P8KJrdd5W)
- Reddit: https://reddit.com/r/VueTube
- Telegram: https://t.me/VueTube
## Builds
[![Build](https://github.com/Frontesque/VueTube/actions/workflows/ci.yml/badge.svg)](https://github.com/Frontesque/VueTube/actions/workflows/ci.yml)

0
scripts/build.sh Normal file → Executable file
View File