├── .gitignore ├── icon.png ├── icon128.png ├── icon16.png ├── icon48.png ├── images ├── demo1.png ├── demo2.png ├── demo3.png ├── demo4.png └── DevpostLogo.png ├── popup.html ├── manifest.json ├── style.css ├── README.md └── script.js /.gitignore: -------------------------------------------------------------------------------- 1 | ignore -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohamedirfansh/Flow/HEAD/icon.png -------------------------------------------------------------------------------- /icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohamedirfansh/Flow/HEAD/icon128.png -------------------------------------------------------------------------------- /icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohamedirfansh/Flow/HEAD/icon16.png -------------------------------------------------------------------------------- /icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohamedirfansh/Flow/HEAD/icon48.png -------------------------------------------------------------------------------- /images/demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohamedirfansh/Flow/HEAD/images/demo1.png -------------------------------------------------------------------------------- /images/demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohamedirfansh/Flow/HEAD/images/demo2.png -------------------------------------------------------------------------------- /images/demo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohamedirfansh/Flow/HEAD/images/demo3.png -------------------------------------------------------------------------------- /images/demo4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohamedirfansh/Flow/HEAD/images/demo4.png -------------------------------------------------------------------------------- /images/DevpostLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohamedirfansh/Flow/HEAD/images/DevpostLogo.png -------------------------------------------------------------------------------- /popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |

Flow video summarizer

11 | 12 | 13 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "Flow - YouTube transcriber & summarizer", 4 | "description": "Make learning from YouTube faster & easier.", 5 | "version": "0.1.0", 6 | "action": { 7 | "default_popup": "popup.html" 8 | }, 9 | "content_scripts": [ 10 | { 11 | "matches": ["https://www.youtube.com/*"], 12 | "js": ["script.js"], 13 | "css": ["style.css"] 14 | } 15 | ], 16 | "icons": { "16": "icon16.png", "48": "icon48.png", "128": "icon128.png" } 17 | } 18 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 3 | } 4 | 5 | .popupWindow { 6 | width: 200px; 7 | height: 200px; 8 | } 9 | 10 | .buttonContainer { 11 | display: flex; 12 | flex-direction: column; 13 | width: 70px; 14 | height: 50px; 15 | background-color: transparent; 16 | } 17 | 18 | .transcribeBox { 19 | font-size: 10px; 20 | border: 1px solid rgb(0, 0, 0, 0.1); 21 | border-radius: 2em; 22 | z-index: 99; 23 | cursor: pointer; 24 | } 25 | 26 | .transcribeBox:hover { 27 | background-color: #6e6d70; 28 | color: white; 29 | } 30 | 31 | .summarizeBox { 32 | font-size: 10px; 33 | border: 1px solid rgb(0, 0, 0, 0.1); 34 | border-radius: 2em; 35 | z-index: 999; 36 | cursor: pointer; 37 | margin-bottom: 2px; 38 | } 39 | 40 | .summarizeBox:hover { 41 | background-color: #6e6d70; 42 | color: white; 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Flow Logo 3 |

4 |

5 | Flow 6 |

7 |

8 | Make learning from YouTube faster & easier ⚡️ 9 |

10 | 11 | ## 📖 Overview 12 | 13 | We're always watching YouTube videos to supplement our learning. We can very often find high quality educational content. The only problem - Our time! 14 | 15 | We have such limited time that revisiting a 2 hour video to find a certain important information is not efficient especially during crunch time. Moreover, the video is soo long that we must write our own summary/pointers to grasp the knowledge better. This is also time-consuming. 16 | 17 | This is where Flow comes in! Flow is your handy chrome extension to speed up & simply your learning from YouTube videos. Every YouTube video will have 2 buttons - `Transcribe` & `Summarize`. 18 | 19 | ![](images/demo1.png) 20 | 21 | ### Transcribe 22 | 23 | Clicking on the `Transcribe` button will produce a full transcript of the video. You can then search for an important pointer from this transcription. 24 | 25 | ![](images/demo2.png) 26 | ![](images/demo3.png) 27 | 28 | ### Summarize 29 | 30 | Clicking on the `Summarize` button will produce a shorter textual version of what was said in the video. Before a quiz/test, this is what you want to be reading! Parts indicated with `[...]` are parts where the algorithm thinks is redundant and thus omitted. You can still view the content by visiting these parts in the full transcript. 31 | 32 | ![](images/demo4.png) 33 | 34 | ## 🔎 How it works 35 | 36 | Retrieving the transcript from a YouTube video is actually not that simple since the YouTube api only allows you to get the transcription for videos where you are the owner. However, everytime a user clicks on a video, the transcript is sent to the client to enable "closed captions". Flow makes use of these through some nifty JavaScript and collects the the full transcript of the video. 37 | 38 | This textual data is then sent to the [Meaning Cloud Text Summarization API](https://learn.meaningcloud.com/developer/summarization/1.0/console) to get the summary. The API performs extractive summarization where only sentences that provide the most info are kept. Each sentence is analyzed given a score based on the TextTeaser & TextRank algorithms. The sentences with the higher score are kept. 39 | 40 | This summary is returned and is shown to the client in a new window for them to copy to their personal notes. 41 | 42 | > The TextTeaser & TextRank algorithms calculate the scores based on the relative position of the sentence in the text, titles and section headers, presence of words in italics and bold, numbers, and/or some special keywords/phrases. 43 | 44 | ## 🚀 Getting Started - Local Development 45 | 46 | ### 📋 Prerequisites 47 | 48 | - Chrome web browser 49 | - Your own API key from [Meaning Cloud](https://learn.meaningcloud.com/developer/summarization/1.0/doc/what-is-summarization) 50 | 51 | ### ⚡️ Installing 🔧 52 | 53 | Download the project using either: 54 | 55 | ``` 56 | git clone https://github.com/mohamedirfansh/Flow.git 57 | ``` 58 | 59 | Or by clicking this [link](https://github.com/mohamedirfansh/Flow/archive/refs/heads/master.zip). 60 | 61 | Then, open `script.js` in your favourite editor and replace line 1 with the API Key you got from [Meaning Cloud](https://learn.meaningcloud.com/developer/summarization/1.0/doc/what-is-summarization). 62 | 63 | Go to `chrome://extensions/` in your browser and enable "Developer mode". Then, click "Load unpacked" and open the folder of this project. Enable the extension and head over to [YouTube](https://www.youtube.com/) to summarize your video! 64 | 65 | --- 66 | 67 | > This project was built during the Hack&Roll 2022 Hackathon. View the Devpost submission [here](https://devpost.com/software/flow-0x8nq2) 68 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | const API_KEY = 'YOUR_API_KEY'; 2 | 3 | const transcriptBox = document.createElement('button'); 4 | transcriptBox.innerHTML = 'transcribe'; 5 | transcriptBox.className = 'transcribeBox'; 6 | 7 | const summarizeBox = document.createElement('button'); 8 | summarizeBox.innerHTML = 'summarize'; 9 | summarizeBox.className = 'summarizeBox'; 10 | 11 | const buttonContainer = document.createElement('div'); 12 | buttonContainer.className = 'buttonContainer'; 13 | buttonContainer.appendChild(transcriptBox); 14 | buttonContainer.appendChild(summarizeBox); 15 | 16 | const videoContainer = document.getElementById('movie_player'); 17 | videoContainer.appendChild(buttonContainer); 18 | 19 | const summaryLength = 75; 20 | 21 | let originalVideoTranscript; 22 | let summarizedVideoTranscript; 23 | 24 | function openTranscriptionBox() { 25 | setTimeout(() => { 26 | document.getElementsByClassName('style-scope ytd-menu-renderer')[6].click(); 27 | setTimeout(() => { 28 | document 29 | .getElementsByClassName('style-scope ytd-menu-service-item-renderer')[4] 30 | .click(); 31 | }, 100); 32 | }, 2500); 33 | } 34 | 35 | function getTranscription() { 36 | const transcriptDivs = document.getElementsByClassName( 37 | 'cue style-scope ytd-transcript-body-renderer' 38 | ); 39 | let transcript = []; 40 | for (let i = 0; i < transcriptDivs.length; i++) { 41 | transcript.push(transcriptDivs[i].innerHTML.trim()); 42 | } 43 | for (let j = 10; j < transcript.length; j += 10) { 44 | transcript.splice(j, 0, '

'); 45 | } 46 | originalVideoTranscript = transcript.join('. '); 47 | } 48 | 49 | function closeTranscriptionBox() { 50 | setTimeout(() => { 51 | document 52 | .getElementsByClassName( 53 | 'style-scope ytd-engagement-panel-title-header-renderer' 54 | )[14] 55 | .click(); 56 | }, 3020); 57 | } 58 | 59 | function transcribeClick() { 60 | openTranscriptionBox(); 61 | setTimeout(getTranscription, 3000); 62 | 63 | setTimeout(() => { 64 | const body = ` 65 |
66 |

Your video transcript:

67 |
68 |
69 |

${originalVideoTranscript}

70 |
71 | `; 72 | const myWindow = window.open('', 'MsgWindow', 'scrollbars=yes'); 73 | myWindow.document.write(body); 74 | console.log(originalVideoTranscript.match(/\w[.?!](\s|$)/g).length); 75 | }, 3010); 76 | 77 | closeTranscriptionBox(); 78 | } 79 | 80 | function summarizeClick() { 81 | openTranscriptionBox(); 82 | setTimeout(getTranscription, 3000); 83 | 84 | setTimeout(() => { 85 | // To send the transcript to api and get the summary back 86 | const formdata = new FormData(); 87 | formdata.append('key', API_KEY); 88 | formdata.append('txt', originalVideoTranscript); 89 | formdata.append('sentences', summaryLength); 90 | 91 | const requestOptions = { 92 | method: 'POST', 93 | body: formdata, 94 | redirect: 'follow', 95 | }; 96 | 97 | const response = fetch( 98 | 'https://api.meaningcloud.com/summarization-1.0', 99 | requestOptions 100 | ) 101 | .then((response) => response.json()) 102 | .then((data) => { 103 | console.log(data); 104 | summarizedVideoTranscript = data.summary; 105 | 106 | const bodySummary = ` 107 |
108 |

Your video summary:

109 |
110 |
111 |

${summarizedVideoTranscript}

112 |
113 | `; 114 | 115 | const myWindow = window.open('', 'MsgWindow', 'scrollbars=yes'); 116 | myWindow.document.write(bodySummary); 117 | }) 118 | .catch((error) => console.log('error', error)); 119 | }, 3010); 120 | 121 | closeTranscriptionBox(); 122 | } 123 | 124 | transcriptBox.onclick = transcribeClick; 125 | summarizeBox.onclick = summarizeClick; 126 | --------------------------------------------------------------------------------