Add Initial PWA Functionality
This commit is contained in:
parent
1dc37d7459
commit
320c305949
|
@ -146,13 +146,17 @@ if (isDevMode) {
|
|||
config.plugins.push(
|
||||
new CopyWebpackPlugin([
|
||||
{
|
||||
from: path.join(__dirname, '../static'),
|
||||
to: path.join(__dirname, '../dist/web/static'),
|
||||
ignore: ['.*'],
|
||||
from: path.join(__dirname, '../static/pwabuilder-sw.js'),
|
||||
to: path.join(__dirname, '../dist/web/pwabuilder-sw.js'),
|
||||
},
|
||||
{
|
||||
from: path.join(__dirname, '../__icons'),
|
||||
to: path.join(__dirname, '../dist/web/icons'),
|
||||
from: path.join(__dirname, '../static'),
|
||||
to: path.join(__dirname, '../dist/web/static'),
|
||||
ignore: ['.*', 'pwabuilder-sw.js'],
|
||||
},
|
||||
{
|
||||
from: path.join(__dirname, '../_icons'),
|
||||
to: path.join(__dirname, '../dist/web/_icons'),
|
||||
ignore: ['.*'],
|
||||
},
|
||||
]),
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<meta charset="utf-8" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="manifest" href="static/manifest.json" />
|
||||
<title></title>
|
||||
<% if (htmlWebpackPlugin.options.nodeModules) { %>
|
||||
<script>
|
||||
|
@ -26,6 +27,28 @@
|
|||
.replace(/\\/g, '\\\\')
|
||||
} catch {}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// This is the service worker with the Advanced caching
|
||||
|
||||
// Add this below content to your HTML page, or add the js file to your page at the very top to register service worker
|
||||
|
||||
// Check compatibility for the browser we're running this in
|
||||
if ("serviceWorker" in navigator) {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
console.log("[PWA Builder] active service worker found, no need to register");
|
||||
} else {
|
||||
// Register the service worker
|
||||
navigator.serviceWorker
|
||||
.register("pwabuilder-sw.js", {
|
||||
scope: "./"
|
||||
})
|
||||
.then(function (reg) {
|
||||
console.log("[PWA Builder] Service worker has been registered for scope: " + reg.scope);
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- webpack builds are automatically injected -->
|
||||
</body>
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
>
|
||||
<input
|
||||
:id="id"
|
||||
v-model="inputData"
|
||||
class="ft-input"
|
||||
type="text"
|
||||
:placeholder="placeholder"
|
||||
@input="e => inputData = e.target.value"
|
||||
>
|
||||
<font-awesome-icon
|
||||
v-if="showArrow"
|
||||
|
|
|
@ -13,6 +13,7 @@ export default Vue.extend({
|
|||
data: () => {
|
||||
return {
|
||||
component: this,
|
||||
windowWidth: 0,
|
||||
showFilters: false
|
||||
}
|
||||
},
|
||||
|
@ -30,6 +31,13 @@ export default Vue.extend({
|
|||
}
|
||||
},
|
||||
mounted: function () {
|
||||
const appWidth = $(window).width()
|
||||
|
||||
if (appWidth <= 680) {
|
||||
const searchContainer = $('.searchContainer').get(0)
|
||||
searchContainer.style.display = 'none'
|
||||
}
|
||||
|
||||
window.addEventListener('resize', function(event) {
|
||||
const width = event.srcElement.innerWidth
|
||||
const searchContainer = $('.searchContainer').get(0)
|
||||
|
@ -43,12 +51,11 @@ export default Vue.extend({
|
|||
},
|
||||
methods: {
|
||||
goToSearch: function (query) {
|
||||
console.log(this)
|
||||
this.showFilters = false
|
||||
const appWidth = $(window).width()
|
||||
|
||||
if (appWidth <= 680) {
|
||||
const searchContainer = $('.searchContainer').get(0)
|
||||
searchContainer.blur()
|
||||
searchContainer.style.display = 'none'
|
||||
}
|
||||
|
||||
|
@ -63,6 +70,8 @@ export default Vue.extend({
|
|||
}
|
||||
}
|
||||
)
|
||||
|
||||
this.showFilters = false
|
||||
},
|
||||
|
||||
toggleSearchContainer: function () {
|
||||
|
|
|
@ -111,10 +111,6 @@ const router = new Router({
|
|||
icon: 'fa-user'
|
||||
},
|
||||
component: Watch
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
redirect: '/subscriptions'
|
||||
}
|
||||
],
|
||||
scrollBehavior (to, from, savedPosition) {
|
||||
|
|
|
@ -30,7 +30,6 @@ export default Vue.extend({
|
|||
showDashPlayer: true,
|
||||
showLegacyPlayer: false,
|
||||
showYouTubeNoCookieEmbed: false,
|
||||
proxyVideos: false,
|
||||
hidePlayer: false,
|
||||
activeFormat: 'legacy',
|
||||
videoId: '',
|
||||
|
@ -65,6 +64,10 @@ export default Vue.extend({
|
|||
return this.$store.getters.getInvidiousInstance
|
||||
},
|
||||
|
||||
proxyVideos: function () {
|
||||
return this.$store.getters.getProxyVideos
|
||||
},
|
||||
|
||||
defaultVideoFormat: function () {
|
||||
return this.$store.getters.getDefaultVideoFormat
|
||||
},
|
||||
|
@ -82,9 +85,15 @@ export default Vue.extend({
|
|||
},
|
||||
|
||||
dashSrc: function () {
|
||||
let url = `${this.invidiousInstance}/api/manifest/dash/${this.videoId}.mpd`
|
||||
|
||||
if (this.proxyVideos) {
|
||||
url = url + '?local=true'
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
url: `${this.invidiousInstance}/api/manifest/dash/${this.videoId}.mpd`,
|
||||
url: url,
|
||||
type: 'application/dash+xml',
|
||||
label: 'Dash',
|
||||
},
|
||||
|
@ -118,10 +127,6 @@ export default Vue.extend({
|
|||
|
||||
this.activeFormat = this.defaultVideoFormat
|
||||
|
||||
if (this.proxyVideos) {
|
||||
this.dashSrc = this.dashSrc + '?local=true'
|
||||
}
|
||||
|
||||
switch (this.backendPreference) {
|
||||
case 'local':
|
||||
this.getVideoInformationLocal()
|
||||
|
@ -239,9 +244,9 @@ export default Vue.extend({
|
|||
})
|
||||
|
||||
if (this.forceLocalBackendForLegacy) {
|
||||
this.videoSourceList = result.formatStreams.reverse()
|
||||
} else {
|
||||
this.getLegacyFormats()
|
||||
} else {
|
||||
this.videoSourceList = result.formatStreams.reverse()
|
||||
}
|
||||
|
||||
this.isLoading = false
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"dir" : "ltr",
|
||||
"lang" : "de",
|
||||
"name" : "FreeTube",
|
||||
"scope" : "/",
|
||||
"display" : "standalone",
|
||||
"start_url" : "https://app.freetubeapp.io/",
|
||||
"short_name" : "FreeTube",
|
||||
"theme_color" : "transparent",
|
||||
"description" : "A description",
|
||||
"orientation" : "any",
|
||||
"background_color" : "transparent",
|
||||
"related_applications" : [],
|
||||
"prefer_related_applications" : false,
|
||||
"icons" : ["/_icons/logoColor.png"],
|
||||
"url" : "https://app.freetubeapp.io",
|
||||
"screenshots" : [],
|
||||
"generated" : "true"
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
// This is the service worker with the Advanced caching
|
||||
|
||||
const CACHE = 'pwabuilder-adv-cache'
|
||||
const precacheFiles = [
|
||||
/* Add an array of files to precache for your app */
|
||||
'index.html',
|
||||
'web.js',
|
||||
'web.css',
|
||||
'static/*',
|
||||
'_icons/*',
|
||||
'fonts/*'
|
||||
]
|
||||
|
||||
// TODO: replace the following with the correct offline fallback page i.e.: const offlineFallbackPage = "offline.html";
|
||||
const offlineFallbackPage = 'index.html'
|
||||
|
||||
const networkFirstPaths = [
|
||||
/* Add an array of regex of paths that should go network first */
|
||||
// Example: /\/api\/.*/
|
||||
]
|
||||
|
||||
const avoidCachingPaths = [
|
||||
/* Add an array of regex of paths that shouldn't be cached */
|
||||
// Example: /\/api\/.*/
|
||||
]
|
||||
|
||||
function pathComparer(requestUrl, pathRegEx) {
|
||||
return requestUrl.match(new RegExp(pathRegEx))
|
||||
}
|
||||
|
||||
function comparePaths(requestUrl, pathsArray) {
|
||||
if (requestUrl) {
|
||||
for (let index = 0; index < pathsArray.length; index++) {
|
||||
const pathRegEx = pathsArray[index]
|
||||
if (pathComparer(requestUrl, pathRegEx)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
self.addEventListener('install', function (event) {
|
||||
console.log('[PWA Builder] Install Event processing')
|
||||
|
||||
console.log('[PWA Builder] Skip waiting on install')
|
||||
self.skipWaiting()
|
||||
|
||||
event.waitUntil(
|
||||
caches.open(CACHE).then(function (cache) {
|
||||
console.log('[PWA Builder] Caching pages during install')
|
||||
|
||||
return cache.addAll(precacheFiles).then(function () {
|
||||
if (offlineFallbackPage === 'ToDo-replace-this-name.html') {
|
||||
return cache.add(new Response('TODO: Update the value of the offlineFallbackPage constant in the serviceworker.'))
|
||||
}
|
||||
|
||||
return cache.add(offlineFallbackPage)
|
||||
})
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
// Allow sw to control of current page
|
||||
self.addEventListener('activate', function (event) {
|
||||
console.log('[PWA Builder] Claiming clients for current page')
|
||||
event.waitUntil(self.clients.claim())
|
||||
})
|
||||
|
||||
// If any fetch fails, it will look for the request in the cache and serve it from there first
|
||||
self.addEventListener('fetch', function (event) {
|
||||
if (event.request.method !== 'GET') return
|
||||
|
||||
if (comparePaths(event.request.url, networkFirstPaths)) {
|
||||
networkFirstFetch(event)
|
||||
} else {
|
||||
cacheFirstFetch(event)
|
||||
}
|
||||
})
|
||||
|
||||
function cacheFirstFetch(event) {
|
||||
event.respondWith(
|
||||
fromCache(event.request).then(
|
||||
function (response) {
|
||||
// The response was found in the cache so we responde with it and update the entry
|
||||
|
||||
// This is where we call the server to get the newest version of the
|
||||
// file to use the next time we show view
|
||||
event.waitUntil(
|
||||
fetch(event.request).then(function (response) {
|
||||
return updateCache(event.request, response)
|
||||
})
|
||||
)
|
||||
|
||||
return response
|
||||
},
|
||||
function () {
|
||||
// The response was not found in the cache so we look for it on the server
|
||||
return fetch(event.request)
|
||||
.then(function (response) {
|
||||
// If request was success, add or update it in the cache
|
||||
event.waitUntil(updateCache(event.request, response.clone()))
|
||||
|
||||
return response
|
||||
})
|
||||
.catch(function (error) {
|
||||
// The following validates that the request was for a navigation to a new document
|
||||
if (event.request.destination !== 'document' || event.request.mode !== 'navigate') {
|
||||
return
|
||||
}
|
||||
|
||||
console.log('[PWA Builder] Network request failed and no cache.' + error)
|
||||
// Use the precached offline page as fallback
|
||||
return caches.open(CACHE).then(function (cache) {
|
||||
cache.match(offlineFallbackPage)
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
function networkFirstFetch(event) {
|
||||
event.respondWith(
|
||||
fetch(event.request)
|
||||
.then(function (response) {
|
||||
// If request was success, add or update it in the cache
|
||||
event.waitUntil(updateCache(event.request, response.clone()))
|
||||
return response
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log('[PWA Builder] Network request Failed. Serving content from cache: ' + error)
|
||||
return fromCache(event.request)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
function fromCache(request) {
|
||||
// Check to see if you have it in the cache
|
||||
// Return response
|
||||
// If not in the cache, then return error page
|
||||
return caches.open(CACHE).then(function (cache) {
|
||||
return cache.match(request).then(function (matching) {
|
||||
if (!matching || matching.status === 404) {
|
||||
return Promise.reject('no-match')
|
||||
}
|
||||
|
||||
return matching
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function updateCache(request, response) {
|
||||
if (!comparePaths(request.url, avoidCachingPaths)) {
|
||||
return caches.open(CACHE).then(function (cache) {
|
||||
return cache.put(request, response)
|
||||
})
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
}
|
Loading…
Reference in New Issue