您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Gartic.io voice input
- // ==UserScript==
- // @name Gartic.io Voice Input
- // @namespace http://tampermonkey.net/
- // @version 2.0
- // @description Gartic.io voice input
- // @author You
- // @match https://*.gartic.io/*
- // @grant none
- // ==/UserScript==
- (function() {
- 'use strict';
- const styles = `
- .voice-container {
- position: fixed;
- top: 80px;
- left: 50%;
- transform: translateX(-50%);
- display: flex;
- gap: 12px;
- z-index: 9999;
- animation: floatIn 0.8s cubic-bezier(0.16, 1, 0.3, 1);
- background: rgba(15, 23, 42, 0.85);
- padding: 12px 20px;
- border-radius: 25px;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3),
- 0 4px 8px rgba(31, 41, 55, 0.2),
- inset 0 2px 5px rgba(255, 255, 255, 0.05);
- backdrop-filter: blur(15px);
- border: 1px solid rgba(255, 255, 255, 0.08);
- }
- .voice-input {
- width: 300px;
- padding: 10px 18px;
- border: 2px solid rgba(255, 255, 255, 0.08);
- border-radius: 18px;
- font-size: 15px;
- background: rgba(255, 255, 255, 0.03);
- color: #fff;
- letter-spacing: 0.3px;
- box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
- transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
- }
- .voice-input::placeholder {
- color: rgba(255, 255, 255, 0.3);
- font-style: italic;
- }
- .voice-input:focus {
- outline: none;
- border-color: rgba(56, 189, 248, 0.5);
- box-shadow: 0 0 20px rgba(56, 189, 248, 0.15),
- inset 0 2px 4px rgba(0, 0, 0, 0.1);
- background: rgba(255, 255, 255, 0.05);
- transform: translateY(-1px);
- }
- .mic-button {
- width: 45px;
- height: 45px;
- border: none;
- border-radius: 50%;
- background: linear-gradient(135deg, #3b82f6, #1d4ed8);
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
- box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3),
- inset 0 -2px 5px rgba(0, 0, 0, 0.2);
- position: relative;
- overflow: hidden;
- }
- .mic-button::before {
- content: '';
- position: absolute;
- top: -50%;
- left: -50%;
- width: 200%;
- height: 200%;
- background: radial-gradient(circle, rgba(255,255,255,0.2) 0%, transparent 70%);
- transform: rotate(45deg);
- transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
- opacity: 0;
- }
- .mic-button:hover::before {
- opacity: 1;
- transform: rotate(225deg);
- }
- .mic-button::after {
- content: '';
- position: absolute;
- width: 100%;
- height: 100%;
- background: linear-gradient(rgba(255, 255, 255, 0.2), transparent);
- clip-path: polygon(0 0, 100% 0, 100% 25%, 0 25%);
- opacity: 0;
- transition: opacity 0.3s;
- }
- .mic-button:hover::after {
- opacity: 1;
- }
- .mic-button:hover {
- transform: translateY(-2px) scale(1.05);
- box-shadow: 0 6px 20px rgba(59, 130, 246, 0.4);
- background: linear-gradient(135deg, #4f46e5, #3b82f6);
- }
- .mic-button:active {
- transform: scale(0.95);
- box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
- }
- .mic-button.recording {
- background: linear-gradient(135deg, #ef4444, #dc2626);
- animation: pulseRecord 2s infinite;
- }
- .mic-icon {
- width: 22px;
- height: 22px;
- fill: white;
- filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.2));
- transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
- }
- .recording .mic-icon {
- animation: scaleIcon 2s infinite;
- filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.5));
- }
- .wave-container {
- position: absolute;
- width: 100%;
- height: 100%;
- pointer-events: none;
- }
- .wave {
- position: absolute;
- border-radius: 50%;
- border: 2px solid rgba(255, 255, 255, 0.4);
- animation: wave 2.5s infinite cubic-bezier(0.4, 0, 0.2, 1);
- opacity: 0;
- }
- .recording .wave-container .wave {
- animation: wave 2s infinite cubic-bezier(0.4, 0, 0.2, 1);
- }
- @keyframes wave {
- 0% {
- width: 0;
- height: 0;
- opacity: 0.8;
- transform: translate(-50%, -50%) rotate(0deg);
- }
- 100% {
- width: 200%;
- height: 200%;
- opacity: 0;
- transform: translate(-50%, -50%) rotate(180deg);
- }
- }
- @keyframes pulseRecord {
- 0% {
- box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.5);
- transform: scale(1);
- }
- 50% {
- box-shadow: 0 0 20px 5px rgba(239, 68, 68, 0.3);
- transform: scale(1.02);
- }
- 100% {
- box-shadow: 0 0 0 0 rgba(239, 68, 68, 0);
- transform: scale(1);
- }
- }
- @keyframes scaleIcon {
- 0%, 100% {
- transform: scale(1) rotate(0deg);
- filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.5));
- }
- 50% {
- transform: scale(0.85) rotate(5deg);
- filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.7));
- }
- }
- @keyframes floatIn {
- 0% {
- transform: translate(-50%, -30px);
- opacity: 0;
- filter: blur(10px);
- }
- 100% {
- transform: translate(-50%, 0);
- opacity: 1;
- filter: blur(0);
- }
- }
- .visualizer {
- position: absolute;
- bottom: -10px;
- left: 0;
- width: 100%;
- height: 2px;
- display: flex;
- justify-content: space-between;
- padding: 0 5px;
- }
- .visualizer-bar {
- width: 2px;
- height: 2px;
- background: rgba(255, 255, 255, 0.5);
- transform-origin: bottom;
- transition: all 0.2s ease;
- border-radius: 2px;
- box-shadow: 0 0 4px rgba(255, 255, 255, 0.3);
- }
- .recording .visualizer-bar {
- animation: glow 1.5s infinite;
- }
- @keyframes glow {
- 0%, 100% {
- box-shadow: 0 0 4px rgba(255, 255, 255, 0.3);
- }
- 50% {
- box-shadow: 0 0 8px rgba(255, 255, 255, 0.5);
- }
- }
- `;
- const styleSheet = document.createElement("style");
- styleSheet.textContent = styles;
- document.head.appendChild(styleSheet);
- const container = document.createElement('div');
- container.className = 'voice-container';
- const input = document.createElement('input');
- input.className = 'voice-input';
- input.type = 'text';
- input.placeholder = 'Konuşmak için mikrofonu tıklayın...';
- const button = document.createElement('button');
- button.className = 'mic-button';
- button.innerHTML = `
- <div class="wave-container">
- <div class="wave"></div>
- <div class="wave" style="animation-delay: 0.4s"></div>
- <div class="wave" style="animation-delay: 0.8s"></div>
- </div>
- <svg class="mic-icon" viewBox="0 0 24 24">
- <path d="M12,2A3,3 0 0,1 15,5V11A3,3 0 0,1 12,14A3,3 0 0,1 9,11V5A3,3 0 0,1 12,2M19,11C19,14.53 16.39,17.44 13,17.93V21H11V17.93C7.61,17.44 5,14.53 5,11H7A5,5 0 0,0 12,16A5,5 0 0,0 17,11H19Z"/>
- </svg>
- <div class="visualizer">
- ${Array(20).fill().map(() => '<div class="visualizer-bar"></div>').join('')}
- </div>
- `;
- let originalSend = WebSocket.prototype.send;
- let wsObj = null;
- WebSocket.prototype.send = function(data) {
- originalSend.apply(this, arguments);
- if (!wsObj) {
- wsObj = this;
- wsObj.addEventListener("message", (msg) => {
- try {
- let data = JSON.parse(msg.data.slice(2));
- if (data[0] == 5) {
- wsObj.lengthID = data[1];
- wsObj.id = data[2];
- wsObj.roomCode = data[3];
- }
- } catch (err) {}
- });
- }
- };
- const sendMessage = (message) => {
- if (wsObj && message.trim()) {
- wsObj.send(`42[11,${wsObj.id},"${message}"]`);
- }
- };
- const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
- recognition.lang = 'tr-TR';
- recognition.continuous = true;
- recognition.interimResults = true;
- let isRecording = false;
- button.addEventListener('click', () => {
- if (!isRecording) {
- recognition.start();
- button.classList.add('recording');
- animateVisualizer(true);
- } else {
- recognition.stop();
- button.classList.remove('recording');
- animateVisualizer(false);
- }
- isRecording = !isRecording;
- });
- input.addEventListener('keypress', (e) => {
- if (e.key === 'Enter') {
- sendMessage(input.value);
- input.value = '';
- }
- });
- recognition.onresult = (event) => {
- const transcript = Array.from(event.results)
- .map(result => result[0])
- .map(result => result.transcript)
- .join('');
- input.value = transcript;
- };
- recognition.onend = () => {
- button.classList.remove('recording');
- isRecording = false;
- animateVisualizer(false);
- };
- function animateVisualizer(active) {
- const bars = document.querySelectorAll('.visualizer-bar');
- if (active) {
- bars.forEach(bar => {
- const animate = () => {
- const height = Math.random() * 20 + 2;
- bar.style.height = `${height}px`;
- bar.style.transform = `scaleY(${height/2})`;
- if (isRecording) {
- requestAnimationFrame(animate);
- }
- };
- animate();
- });
- } else {
- bars.forEach(bar => {
- bar.style.height = '2px';
- bar.style.transform = 'scaleY(1)';
- });
- }
- }
- container.appendChild(input);
- container.appendChild(button);
- document.body.appendChild(container);
- })();