您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add a spectrogram to iNaturalist audio
- // ==UserScript==
- // @name iNaturalist Spectrogram
- // @namespace https://greasyfork.org/users/170755
- // @version 2024-01-26
- // @description Add a spectrogram to iNaturalist audio
- // @author w_biggs
- // @match https://www.inaturalist.org/observations/*
- // @grant none
- // @require https://cdn.jsdelivr.net/gh/w-biggs/spectrogramJS@68733ac9f61f21dd21ec9b0f4c5727c9da8a5bb4/js/spectrogram.js
- // @require https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js
- // @require https://cdn.jsdelivr.net/gh/stdlib-js/stats-base-dists-beta-cdf@48e844d06dc88c834ac95568af5207d56438297a/browser.js
- // @license MIT
- // ==/UserScript==
- (function() {
- 'use strict';
- const spectrogramCSS = `
- .spectrogram canvas, .spectrogram svg {
- position: absolute;
- top: 0;
- left: 0;
- }
- .spectrogram {
- position: relative;
- color: black;
- pointer-events: auto;
- }
- .axis {
- font: 14px sans-serif;
- }
- .axis path, .axis line {
- fill: none;
- }
- .axis line {
- shape-rendering: crispEdges;
- stroke: #444;
- stroke-width: 1.0px;
- stroke-dasharray: 2, 4;
- }
- #progress-line {
- stroke: #a50f15;
- stroke-width: 4px;
- }
- #ObservationShow .top_row .photos_column .PhotoBrowser .image-gallery-slide .sound-container {
- transform: translateY(-50%);
- }`
- const style = document.createElement('style');
- style.textContent = spectrogramCSS;
- document.head.appendChild(style);
- const rgbToHex = (r, g, b) => '#' + [r, g, b].map(x => {
- const hex = x.toString(16)
- return hex.length === 1 ? '0' + hex : hex
- }).join('');
- const a = 1;
- const b = 1;
- const threshold = 1;
- const granularity = 100;
- const colorSchemeBase = [];
- for (let i = 0; i <= granularity; i++) {
- colorSchemeBase.push(1 - ((1 / granularity) * i));
- }
- // console.log(colorSchemeBase);
- const colorScheme = colorSchemeBase.map(num => Math.min(1, 1 - ((1 - num) / threshold)))
- .map(num => cdf(num, a, b))
- .map(y => {
- const black = Math.round(y * 255);
- return rgbToHex(black, black, black);
- });
- // console.log(`color scheme: ${colorScheme.join(', ')}`);
- const waitForEl = selector => {
- return new Promise(resolve => {
- if (document.querySelector(selector)) {
- return resolve(document.querySelector(selector));
- }
- const observer = new MutationObserver(mutations => {
- if (document.querySelector(selector)) {
- observer.disconnect();
- resolve(document.querySelector(selector));
- }
- });
- observer.observe(document.body, {
- childList: true,
- subtree: true
- });
- });
- }
- const specs = [];
- const createSpec = (soundContainer, index) => {
- if (soundContainer.querySelector('.sound').hidden) {
- soundContainer.querySelector('.sound').hidden = false;
- soundContainer.querySelector('.spectrogram').hidden = true;
- } else {
- const spectrogramEl = document.createElement('div');
- const specId = `spec-${index}`;
- spectrogramEl.id = specId;
- spectrogramEl.classList.add('spectrogram');
- const sourceEl = soundContainer.querySelector('source');
- const audioUrl = sourceEl.src;
- soundContainer.prepend(spectrogramEl);
- const spec = new Spectrogram(audioUrl, `#${specId}`, {
- width: 480,
- height: 200,
- maxFrequency: 10000,
- colorScheme: colorScheme,
- decRange: [-100, 0],
- sampleSize: 256
- });
- specs.push(spec);
- soundContainer.querySelector('.sound').hidden = true;
- }
- /* for (const spec of specs) {
- console.log(spec.colorScheme);
- } */
- };
- waitForEl('.sound-container source').then(() => {
- const soundContainers = document.getElementsByClassName('sound-container');
- for (let i = 0; i < soundContainers.length; i++) {
- const soundContainer = soundContainers[i];
- const captionsBox = soundContainer.querySelector('.captions-box');
- const button = document.createElement('button');
- button.classList.add('btn');
- button.classList.add('btn-nostyle');
- button.textContent = 'Toggle spectrogram';
- button.addEventListener('click', () => createSpec(soundContainer, i));
- captionsBox.appendChild(button);
- }
- });
- })();