Browse Source

WIP creating bookmarks

undefined
Gerben 4 years ago
parent
commit
a280310d7a
9 changed files with 150 additions and 4 deletions
  1. +8
    -0
      app/_locales/en/messages.json
  2. +7
    -3
      app/audio-player/contentscript.js
  3. +30
    -0
      app/create-bookmarks/background.js
  4. +76
    -0
      app/create-bookmarks/contentscript.js
  5. +2
    -0
      app/manifest.json
  6. +1
    -0
      app/scripts/background.js
  7. +1
    -0
      app/scripts/contentscript.js
  8. +23
    -0
      package-lock.json
  9. +2
    -1
      package.json

+ 8
- 0
app/_locales/en/messages.json View File

@@ -10,5 +10,13 @@
"appDescription": {
"message": "Browser extension to bookmark fragments of audio files",
"description": "The description of the application"
},
"bookmarkSelectionContextMenuItemForFragment": {
"message": "Bookmark selected fragment",
"description": "The entry in the context ('right-click') menu when selecting an audio fragment"
},
"bookmarkSelectionContextMenuItemForSingleMoment": {
"message": "Bookmark selected moment",
"description": "The entry in the context ('right-click') menu when selecting a single moment"
}
}

+ 7
- 3
app/audio-player/contentscript.js View File

@@ -61,7 +61,7 @@ async function init() {


// Bind window hash change to update player
window.addEventListener('hashchange', async function() {
window.addEventListener('hashchange', async function() {
if(playlist.isPlaying()) {
eventEmitter.emit('stop')
// pause needs a small delay, coz the lib doesn't
@@ -72,7 +72,6 @@ async function init() {
eventEmitter.emit('play');
});

// Load Playlist
await playlist.load([{
src: document.URL
@@ -83,6 +82,11 @@ async function init() {

// Start playing. A tiny delay seems needed in Firefox to show the cursor at the right place.
requestAnimationFrame(() => eventEmitter.emit('play'));

return playlist;
}

init();
init().then(playlist => {
// Store playlist as a shared global variable.
self.playlist = playlist;
});

+ 30
- 0
app/create-bookmarks/background.js View File

@@ -0,0 +1,30 @@
import { makeRemotelyCallable, remoteFunction } from 'webextension-rpc';

function createPreciseUrl(url, selector) {
const properUrl = url.split('#')[0];

let fragmentIdentifier;
if (selector.type === 'FragmentSelector') {
fragmentIdentifier = selector.value;
} else {
throw new Error('Unsupported selector type');
}

return properUrl + '#' + fragmentIdentifier;
}

async function createBookmark({ tab }) {
const selector = await remoteFunction('describeSelection', { tabId: tab.id })();
const bookmarkUrl = createPreciseUrl(tab.url, selector);
const filenameMatch = tab.url.match(/.*\/([^\/#?]+)(?:\?.*)?(?:#.*)?/);
const filename = filenameMatch ? filenameMatch[1] : 'Audio fragment';

const bookmarkTitle = `${filename} ${start}–${end}`;

await browser.bookmarks.create({
title: bookmarkTitle,
url: bookmarkUrl,
});
}

makeRemotelyCallable({ createBookmark }, { insertExtraArg: true });

+ 76
- 0
app/create-bookmarks/contentscript.js View File

@@ -0,0 +1,76 @@
import delay from 'delay';
import { makeRemotelyCallable, remoteFunction } from 'webextension-rpc';

function describeSelection() {
const playlist = self.playlist;
if (!playlist) {
throw new Error('Player has not been initialised.');
}

let { start, end } = playlist.getTimeSelection();
// Waveform Playlist tells us end=start when the selection is just a single line.
if (end === start) end = undefined;
// Round the numbers to two decimals.
if (start !== undefined) start = Math.round(start * 100) / 100;
if (end !== undefined) end = Math.round(end * 100) / 100;

const fragmentIdentifier = `t=${start || ''}` + (end ? `,${end}` : '');

const selector = {
type: 'FragmentSelector',
conformsTo: 'http://www.w3.org/TR/media-frags/',
value: fragmentIdentifier,
};
return selector;
}

makeRemotelyCallable({
describeSelection,
});

async function init() {
let menuEl;

function cleanupMenu() {
if (!menuEl) return;
menuEl.parentNode.removeChild(menuEl);
menuEl = undefined;
}

function onContextMenu(event) {
event.preventDefault();
const left = event.pageX;
const top = event.pageY;

const playlist = self.playlist;
if (!playlist) {
throw new Error('Player has not been initialised.');
}
let { start, end } = playlist.getTimeSelection();
const fragmentIsSelected = start !== end;

cleanupMenu();
menuEl = document.createElement('ul');
const liEl = document.createElement('li');
menuEl.appendChild(liEl);
menuEl.setAttribute('style', `list-style: none; margin: 0; padding: 0; position: absolute; top: ${top}; left: ${left}; z-index: 9999999; background: #eee; border: 1px solid black;`);

const buttonEl = document.createElement('button');
buttonEl.innerText = browser.i18n.getMessage(fragmentIsSelected
? 'bookmarkSelectionContextMenuItemForFragment'
: 'bookmarkSelectionContextMenuItemForSingleMoment'
);
buttonEl.addEventListener('click', remoteFunction('createBookmark'));

liEl.appendChild(buttonEl);
document.body.appendChild(menuEl);
}

document.addEventListener('contextmenu', onContextMenu, false);

document.addEventListener('click', event => {
cleanupMenu();
})
}

init();

+ 2
- 0
app/manifest.json View File

@@ -10,6 +10,8 @@
},
"permissions": [
"<all_urls>",
"bookmarks",
"tabs",
"webRequest"
]
}

+ 1
- 0
app/scripts/background.js View File

@@ -1 +1,2 @@
import '../audio-player/background.js'
import '../create-bookmarks/background.js'

+ 1
- 0
app/scripts/contentscript.js View File

@@ -1 +1,2 @@
import '../audio-player/contentscript.js'
import '../create-bookmarks/contentscript.js'

+ 23
- 0
package-lock.json View File

@@ -5524,6 +5524,29 @@
"integrity": "sha512-ISB42vlgMyM7xE1u6pREeCqmmXjLsYu/nqAR8Dl/gIAnylb+KpRpvKbVkUYNFePhhXn0Obkkc3jasOII9ztUtg==",
"dev": true
},
"webextension-rpc": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/webextension-rpc/-/webextension-rpc-0.1.0.tgz",
"integrity": "sha512-9JCBkXmeP7ossYauXgfvxqQurO5E0VK7uQnlIyirj1zzhGzV92TvOC4FhhqhYBphV9d0doUg+pCQtvRkGsk8+A==",
"requires": {
"@babel/runtime": "^7.6.2"
},
"dependencies": {
"@babel/runtime": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz",
"integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==",
"requires": {
"regenerator-runtime": "^0.13.2"
}
},
"regenerator-runtime": {
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
"integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw=="
}
}
},
"webextension-toolbox": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/webextension-toolbox/-/webextension-toolbox-3.0.0.tgz",


+ 2
- 1
package.json View File

@@ -16,6 +16,7 @@
},
"dependencies": {
"delay": "^4.3.0",
"waveform-playlist": "^3.0.4"
"waveform-playlist": "^3.0.4",
"webextension-rpc": "^0.1.0"
}
}

Loading…
Cancel
Save