Skip to content

Commit

Permalink
Added a popup to load annotation data
Browse files Browse the repository at this point in the history
  • Loading branch information
isaackd committed Jan 19, 2019
1 parent 8a0618c commit f45ff0f
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

*.zip
7 changes: 3 additions & 4 deletions js/AnnotationParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,8 @@ class AnnotationParser {
const dom = parser.parseFromString(xml, "application/xml");
return dom;
}
getAnnotationsFromXml(xmlDom) {
const parser = new DOMParser();
const dom = parser.parseFromString(xmlDom, "application/xml");
getAnnotationsFromXml(xml) {
const dom = this.xmlToDom(xml);
return dom.getElementsByTagName("annotation");
}
parseYoutubeFormat(annotationElements) {
Expand Down Expand Up @@ -278,4 +277,4 @@ class AnnotationParser {
}
}
}
}
}
20 changes: 19 additions & 1 deletion js/AnnotationRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ class AnnotationRenderer {
this.updateInterval = updateInterval;

}
changeAnnotationData(annotations) {
this.stop();
this.removeAnnotationElements();
this.annotations = annotations;
this.createAnnotationElements();
this.start();
}
createAnnotationElements() {
for (const annotation of this.annotations) {
const el = document.createElement("div");
Expand All @@ -49,7 +56,13 @@ class AnnotationRenderer {
this.annotationsContainer.append(el);
}
}
removeAnnotationElements() {
for (const annotation of this.annotations) {
annotation.__element.remove();
}
}
update(videoTime) {
console.log("updating: ", videoTime);
for (const annotation of this.annotations) {
const el = annotation.__element;
const start = annotation.timeStart;
Expand All @@ -63,6 +76,11 @@ class AnnotationRenderer {
}
}
}
hideAll() {
for (const annotation of this.annotations) {
annotation.__element.setAttribute("hidden", "");
}
}
start() {
window.postMessage({type: "__annotations_restored_renderer_start", updateInterval: this.updateInterval}, this.postMessageOrigin);
}
Expand Down Expand Up @@ -94,4 +112,4 @@ class AnnotationRenderer {
this.stop();
this.start();
}
}
}
4 changes: 3 additions & 1 deletion js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (videoId) {

chrome.tabs.sendMessage(tab.id, {type: "check_description_for_annotations"}, response => {
console.log(response);
if (response.requestAnnotations) {
const requestUrl = annotationsEndpoint + videoId;
console.log(`Loading annotations for '${videoId}' from '${requestUrl}'`);
Expand All @@ -22,7 +23,8 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
chrome.tabs.sendMessage(tab.id, {type: "annotations_unavailable"});
}
}).catch(e => {
throw e;
console.log("Annotation data is unavailable for this video");
chrome.tabs.sendMessage(tab.id, {type: "annotations_unavailable"});
});
}
else {
Expand Down
55 changes: 44 additions & 11 deletions js/content.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const annotationParser = new AnnotationParser();
let renderer;

function setupExternalScript() {
// must be done this way due to the "x-ray" mode the content scripts are run in
Expand All @@ -11,17 +12,21 @@ function setupExternalScript() {
const data = e.data;
const type = data.type;
if (type === "__annotations_restored_renderer_start") {
rendererUpdateIntervalId = setInterval(() => {
const videoTime = player.getCurrentTime();
const updateEvent = new CustomEvent("__annotations_restored_renderer_update", {
detail: {videoTime}
});
window.dispatchEvent(updateEvent)
}, data.updateInterval);
if (!rendererUpdateIntervalId) {
rendererUpdateIntervalId = setInterval(() => {
const videoTime = player.getCurrentTime();
const updateEvent = new CustomEvent("__annotations_restored_renderer_update", {
detail: {videoTime}
});
window.dispatchEvent(updateEvent)
}, data.updateInterval);
}
}
else if (type === "__annotations_restored_renderer_stop") {
clearInterval(rendererUpdateIntervalId);
rendererUpdateIntervalId = null;
if (rendererUpdateIntervalId) {
clearInterval(rendererUpdateIntervalId);
rendererUpdateIntervalId = null;
}
}
else if (type === "__annotations_restored_renderer_seek_to") {
player.seekTo(data.seconds);
Expand All @@ -43,6 +48,8 @@ function setupExternalScript() {
document.body.append(script);
}

setupExternalScript();

function getAnnotationsFromDescription() {
return new Promise((resolve, reject) => {
let intervalCount = 0;
Expand Down Expand Up @@ -94,9 +101,9 @@ function getAnnotationsFromDescription() {
}

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log(request);
if (request.type === "check_description_for_annotations") {
getAnnotationsFromDescription().then(annotations => {
setupExternalScript();
const videoContainer = document.getElementById("movie_player");
renderer = new AnnotationRenderer(annotations, videoContainer, videoContainer);
renderer.start();
Expand All @@ -112,7 +119,6 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
const annotationData = request.xml;
if (annotationData) {
console.info("Received annotation data from server");
setupExternalScript();
const annotationDom = annotationParser.xmlToDom(annotationData);
const annotationElements = annotationDom.getElementsByTagName("annotation");

Expand All @@ -126,4 +132,31 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
else if (request.type === "annotations_unavailable") {
console.info("Annotation data for this video is unavailable");
}
// popup annotation loading
else if (request.type === "popup_load_youtube" && request.data) {
console.info("loading youtube data");
const annotationDom = annotationParser.xmlToDom(request.data);
const annotationElements = annotationDom.getElementsByTagName("annotation");
const annotations = annotationParser.parseYoutubeFormat(annotationElements);
if (!renderer) {
const videoContainer = document.getElementById("movie_player");
renderer = new AnnotationRenderer(annotations, videoContainer, "https://www.youtube.com/");
renderer.start();
}
else {
renderer.changeAnnotationData(annotations);
}
}
else if (request.type === "popup_load_converted" && request.data) {
console.info("loading converted data");
const annotations = annotationParser.deserializeAnnotationList(request.data);
if (!renderer) {
const videoContainer = document.getElementById("movie_player");
renderer = new AnnotationRenderer(annotations, videoContainer, "https://www.youtube.com/");
renderer.start();
}
else {
renderer.changeAnnotationData(annotations);
}
}
});
5 changes: 5 additions & 0 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
"permissions": [
"tabs"
],
"browser_action": {
"default_title": "Annotations Restored",
"default_popup": "popup/index.html"
},

"content_scripts": [{
"matches": ["*://www.youtube.com/watch?*"],
"js": ["js/AnnotationParser.js", "js/AnnotationRenderer.js", "js/content.js"],
Expand Down
16 changes: 16 additions & 0 deletions popup/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
textarea {
width: 98%;
height: 5rem;
}
input {
margin-bottom: 0.5rem;
}
#buttons {
display: flex;
width: 100%;

justify-content: center;
}
#buttons > input:first-child {
margin-right: 1rem;
}
22 changes: 22 additions & 0 deletions popup/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
<h3>YouTube Annotation Data</h3>
<input id="youtube-file" type="file">
<textarea id="youtube-data" placeholder="YouTube Annotation Data..."></textarea>
<h3>Converted YouTube Annotation Data</h3>
<input id="converted-file" type="file">
<textarea id="converted-data" placeholder="Converted YouTube Annotation Data..."></textarea>

<div id="buttons">
<input id="load-youtube" type="button" value="Load YouTube Data">
<input id="load-converted" type="button" value="Load Converted Data">
</div>

<script type="text/javascript" src="index.js"></script>
</body>
</html>
40 changes: 40 additions & 0 deletions popup/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const youtubeFile = document.getElementById("youtube-file");
const youtubeTextArea = document.getElementById("youtube-data");

const convertedFile = document.getElementById("converted-file");
const convertedTextArea = document.getElementById("converted-data");

const loadYoutube = document.getElementById("load-youtube");
const loadConverted = document.getElementById("load-converted");

loadYoutube.addEventListener("click", e => {
const data = youtubeTextArea.value;
sendLoadMessage("popup_load_youtube", data);
});
loadConverted.addEventListener("click", e => {
const data = convertedTextArea.value;
sendLoadMessage("popup_load_converted", data);
});

youtubeFile.addEventListener("change", e => loadFileData(youtubeFile.files[0], youtubeTextArea));
convertedFile.addEventListener("change", e => loadFileData(convertedFile.files[0], convertedTextArea));

function loadFileData(file, textarea) {
const reader = new FileReader();
reader.addEventListener("load", e => {
textarea.value = reader.result;
});
reader.readAsText(file);
}

function sendLoadMessage(type, data) {
if (!type || !data) return;
console.log("sending load message:", type);
chrome.tabs.query({currentWindow: true, active: true}, tabs => {
if (tabs[0]) {
const tab = tabs[0];
console.log(tab);
chrome.tabs.sendMessage(tab.id, {type, data});
}
});
}

0 comments on commit f45ff0f

Please sign in to comment.