Skip to content

Instantly share code, notes, and snippets.

@Tuurash
Last active July 3, 2025 15:03
Show Gist options
  • Select an option

  • Save Tuurash/0c23bcfba2a463b92ed90d8fed464029 to your computer and use it in GitHub Desktop.

Select an option

Save Tuurash/0c23bcfba2a463b92ed90d8fed464029 to your computer and use it in GitHub Desktop.
Turn any site into an app — impress no one but feel productive.
// ==UserScript==
// @name PWAny
// @namespace https://gist.github.com/Tuurash/0c23bcfba2a463b92ed90d8fed464029/raw/f2ffa5f8bc850dec75959dd39aa64704a356276e/PWAny.user.js
// @version 1.2
// @description Inject PWA capabilities into websites via context menu
// @author tuurash
// @match *://*/*
// @run-at document-idle
// @grant GM_notification
// @grant GM_registerMenuCommand
// ==/UserScript==
(function() {
'use strict';
// Configuration
const config = {
checkExisting: true // Check for existing PWA elements
};
let injectionStatus = {
manifest: { injected: false, preExisting: false },
serviceWorker: { injected: false, preExisting: false }
};
// Main initialization
function init() {
// Removed automatic injection
registerMenuCommands();
}
// Register Tampermonkey menu commands
function registerMenuCommands() {
if (typeof GM_registerMenuCommand !== 'undefined') {
// Primary injection command
GM_registerMenuCommand('Inject PWA Capabilities', () => {
attemptPWAInjection();
showNotification('PWA components injected!');
});
// Status check command
GM_registerMenuCommand('Show PWA Injection Status', showInjectionStatus);
}
}
// Core injection logic
function attemptPWAInjection() {
checkExistingPWA();
if (!injectionStatus.manifest.preExisting) {
injectManifest();
}
if (!injectionStatus.serviceWorker.preExisting) {
injectServiceWorker();
}
showInjectionStatus();
}
// Check for existing PWA components
function checkExistingPWA() {
// Check for existing manifest
const existingManifest = document.querySelector('link[rel="manifest"]');
injectionStatus.manifest.preExisting = !!existingManifest;
// Check for existing service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations().then(registrations => {
injectionStatus.serviceWorker.preExisting = registrations.length > 0;
});
}
}
// Inject Web App Manifest
function injectManifest() {
try {
const manifest = {
name: document.title || 'PWA Enabled Site',
short_name: document.title.substring(0, 12) || 'PWA Site',
start_url: window.location.href,
display: 'standalone',
background_color: '#ffffff',
theme_color: '#3f51b5',
icons: [{
src: getSiteIcon(),
sizes: '192x192',
type: 'image/png'
}]
};
const blob = new Blob([JSON.stringify(manifest)], {type: 'application/json'});
const manifestURL = URL.createObjectURL(blob);
const link = document.createElement('link');
link.rel = 'manifest';
link.href = manifestURL;
document.head.appendChild(link);
injectionStatus.manifest.injected = true;
return true;
} catch (e) {
console.error('Manifest injection failed:', e);
return false;
}
}
// Get best available site icon
function getSiteIcon() {
try {
const icons = [
...document.querySelectorAll('link[rel="icon"], link[rel="shortcut icon"]'),
...document.querySelectorAll('meta[property="og:image"]')
];
return icons.length > 0 ?
(icons[0].href || icons[0].content) :
`${window.location.origin}/favicon.ico`;
} catch (e) {
return 'https://via.placeholder.com/192/3f51b5/ffffff?text=PWA';
}
}
// Inject Service Worker
function injectServiceWorker() {
if (!('serviceWorker' in navigator)) return false;
try {
const swCode = `
self.addEventListener('install', () => self.skipWaiting());
self.addEventListener('activate', event => event.waitUntil(self.clients.claim()));
`;
const blob = new Blob([swCode], {type: 'application/javascript'});
const swURL = URL.createObjectURL(blob);
navigator.serviceWorker.register(swURL, {
scope: './',
updateViaCache: 'none'
}).then(registration => {
console.log('Service Worker registered:', registration);
injectionStatus.serviceWorker.injected = true;
}).catch(e => {
console.error('Service Worker registration failed:', e);
});
return true;
} catch (e) {
console.error('Service Worker injection failed:', e);
return false;
}
}
// Show injection status
function showInjectionStatus() {
const manifestStatus = injectionStatus.manifest.injected ?
'✅ Injected' : injectionStatus.manifest.preExisting ?
'⚠️ Pre-existing' : '❌ Not injected';
const swStatus = injectionStatus.serviceWorker.injected ?
'✅ Injected' : injectionStatus.serviceWorker.preExisting ?
'⚠️ Pre-existing' : '❌ Not injected';
const message = `PWA Status for ${window.location.host}:
• Manifest: ${manifestStatus}
• Service Worker: ${swStatus}
Note: Browser may require page reload to detect changes.`;
showNotification(message, 7000);
}
// Show notification
function showNotification(message, duration = 5000) {
if (typeof GM_notification === 'function') {
GM_notification({
title: 'PWAny',
text: message,
timeout: duration,
silent: true
});
} else {
// Fallback notification
const notification = document.createElement('div');
notification.style = `
position: fixed;
bottom: 20px;
right: 20px;
padding: 15px;
background: #333;
color: white;
border-radius: 8px;
z-index: 9999;
font-family: sans-serif;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
max-width: 300px;
white-space: pre-line;
font-size: 14px;
`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => {
notification.style.opacity = '0';
notification.style.transition = 'opacity 0.5s';
setTimeout(() => notification.remove(), 500);
}, duration);
}
}
// Start the script
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment