Skip to content

Commit

Permalink
marked and button and iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
Laurent Denoue committed Nov 27, 2024
1 parent 2cdc256 commit 7a6ff28
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 34 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
This repo shows how to fetch the raw YouTube transcripts and use the Gemini Flash 8B API to format them.
Made by [ldenoue](https://twitter.com/ldenoue)

[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/ldenoue)

# How to use

open https://ldenoue.github.io/readabletranscripts and type any search term
Expand Down
71 changes: 46 additions & 25 deletions code.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,8 @@ async function getModelAnswer(prompt, maxretry = 4) {
const priceInput = computePrice(inputTokens, inputPrice)
const priceOutput = computePrice(outputTokens, outputPrice)
const priceTotal = priceInput + priceOutput
usageDiv.textContent = `for ${simulatedUsers.toLocaleString()} users: ${inputTokens} ${formatPrice(priceInput)} ${outputTokens} ${formatPrice(priceOutput)} ${totalTokens} ${formatPrice(priceTotal)}`
usageDiv.textContent = `Input #${inputTokens}=${formatPrice(priceInput)} Output #${outputTokens}=${formatPrice(priceOutput)} #${totalTokens}=${formatPrice(priceTotal)}`
usageDiv.style.display = 'block'
return res
} catch (error) {
if (error.message && error.message.indexOf('API_KEY_INVALID')) {
Expand Down Expand Up @@ -353,7 +354,6 @@ async function punctuateText(c, vocab = '', lang = 'en', p = null) {
async function mergeSentences(a, b, vocab, languageCode = 'en') {
let res = await punctuateText(clean(a) + ' ' + clean(b), vocab, languageCode, `please fix this sentence, without paragraphrasing, write in ${languageName(languageCode)}: `)
res = res.replace(/\s+/g, ' ')
console.log('merge=', res)
return res
}

Expand All @@ -376,18 +376,15 @@ function clean(a) {
}

function getWords(text) {
let paragraphs = text.split('\n')
let paragraphs = text.split('\n').filter(p => p > '')
let res = []
for (let p of paragraphs) {
// modern-day startups b1cicJ3OTvg
let words = p.split(/[\s-]+/).map(a => new Object({ o: a, w: a.trim().toLowerCase().replace(/\W+/g, '') }))
//words = words.filter(w => w.o > '')
if (words.length > 0) {
if (words.length > 0 && words[0].o > '') {
words[0].p = true
}
res = res.concat(words)
}
//console.log(res)
return res
}
function prepareWords(chunks) {
Expand Down Expand Up @@ -504,6 +501,12 @@ function insertChapter(p, c) {
//p.innerHTML = '<h4>' + c.text + '</h4>' + p.innerHTML
p.parentElement.insertBefore(header, p)
}

function numberedItem(w) {
if (w === '*')
return true
return w.match(/^\d\./g) !== null
}
function endOfSentence(w) {
const ends = ['.', '?', '!']
if (!(w > ''))
Expand All @@ -529,10 +532,10 @@ function msToTime(duration) {
function buildWords(words, r = punctuated) {
let p = null
let end = false
let inBold = false
for (let w of words) {
if (w.o === '.')
continue
const key = w.o + '-' + w.s
if (end) {
for (let c of chapters) {
if (!c.taken && c.start <= w.s + 1000 && !c.taken) {
Expand All @@ -542,17 +545,23 @@ function buildWords(words, r = punctuated) {
}
end = endOfSentence(w.o)
if (w.p && w.o > '') {
console.log(w)
p = document.createElement('p')
p.className = 'p'
p.start = w.s
let ts = document.createElement('div')
ts.className = 'ts'
ts.start = w.s
ts.textContent = msToTime(p.start)
ts.addEventListener('click', () => {
play(ts.start)
})
p.appendChild(ts)
if (w.p && !numberedItem(w.o)) {
let ts = document.createElement('div')
ts.className = 'ts'
ts.start = w.s
ts.textContent = msToTime(p.start)
ts.addEventListener('click', () => {
play(ts.start)
})
p.appendChild(ts)
} else {
p.classList.add('plist')
w.o = '- '
}
r.appendChild(p)
for (let c of chapters) {
if (c.start <= w.s + 1000 && !c.taken) {
Expand All @@ -563,6 +572,20 @@ function buildWords(words, r = punctuated) {
if (w.o === '')
continue
let span = document.createElement('span')
if (w.o.indexOf('```') !== -1) {
inCode = true
} else {
if (w.o.indexOf('`') === 0) {
w.o = w.o.substring(1)
inBold = true
}
if (inBold)
span.classList.add('bold')
if (w.o.indexOf('`') > 0) {
inBold = false
w.o = w.o.substring(0,w.o.length-1)
}
}
span.textContent = w.o + ' '
if (w.s !== undefined) {
span.o = w.o
Expand Down Expand Up @@ -1176,8 +1199,10 @@ async function punctuate(videoId, languageCode = 'en') {
chapters = parseYTChapters(json.chapters) ?? []
if (chapters.length === 0)
chapters = computeChapters(json.description)
videoDuration = json.duration
vtitle.textContent = json.title
vurl.textContent = vurl.href = `https://www.youtube.com/watch?v=${videoId}`
vduration.textContent = msToTime(videoDuration * 1000)

thumb.src = `https://img.youtube.com/vi/${videoId}/mqdefault.jpg`
const img = new Image(thumb.src)
Expand All @@ -1200,7 +1225,6 @@ async function punctuate(videoId, languageCode = 'en') {
json.chunks = json[languageCode].chunks
json.text = json.chunks.map(c => c.text).join(' ')
let transcript = json.text
videoDuration = json.duration
const videoTitle = json.title || ''
const videoDescription = json.description || ''

Expand All @@ -1219,15 +1243,16 @@ async function punctuate(videoId, languageCode = 'en') {
let startTime = Date.now()
let chunks = chunkText(transcript, chunkSize)
console.log('n chunks=', chunks.length)
const DEBUG = false
const puncKey = languageCode + '-punc-' + videoId
const prevPunctuatedText = await localforage.getItem(puncKey)
if (!DEBUG && prevPunctuatedText) {
if (prevPunctuatedText) {
let punctuatedText = prevPunctuatedText
let punctuatedTimes = testDiff(wordTimes, punctuatedText)
punctuated.innerHTML = ''
console.log('here')
buildWords(punctuatedTimes)
window.punctuatedText = punctuatedText
window.punctuatedTimes = punctuatedTimes
punctuated.innerHTML = marked(punctuatedText)
//buildWords(punctuatedTimes)
return
}
let promises = []
Expand Down Expand Up @@ -1261,11 +1286,9 @@ async function punctuate(videoId, languageCode = 'en') {
let merged = mergeSentences(a.end, b.start, vocab, languageCode)
merges.push(merged)
}
console.log('waiting for merges', merges.length)
let fragments = await Promise.all(merges)
let punctuatedText = parts[0].left
for (let i = 0; i < fragments.length; i++) {
//console.log(i, parts[i])
punctuatedText += ' ' + fragments[i] + ' ' + parts[i].right
}
punctuatedText = punctuatedText.replace(/,\s+/g, ', ')
Expand Down Expand Up @@ -1312,10 +1335,8 @@ keyBtn.onclick = () => {
function startObserving() {
const target = document.getElementById("playercontainer");
const marker = document.getElementById("marker");

const observer = new IntersectionObserver(
(entries) => {
console.log(entries)
entries.forEach((entry) => {
if (!entry.isIntersecting) {
target.classList.add("fixed");
Expand Down
6 changes: 3 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@
<h1><a href="/readabletranscripts">Readable Transcripts</a></h1>
<form method="get">
<div class="flexrow">
<input type="text" name="q" id="q" size="40" placeholder="search or paste YouTube link" value="">
<input type="text" name="q" id="q" placeholder="YouTube link or query" value="">
<button type="submit" id="searchBtn">Search</button>
</div>
</form>
<form method="get">
<div class="flexrow">
<input type="text" id="apiKey" size="40" placeholder="Gemini API Key" value="">
<input type="text" id="apiKey" placeholder="Gemini API Key" value="">
<button type="submit" id="keyBtn">Set Key</button>
</div>
</form>
Expand All @@ -43,7 +43,7 @@ <h1><a href="/readabletranscripts">Readable Transcripts</a></h1>
<div class="column" id="col1">
<h2><a href="/readabletranscripts"><i class="btn fa-solid fa-home"></i></a></h2>
<b id="vtitle"></b>
<a id="vurl" target="_blank" href=""></a>
<div><span id="vduration"></span> <a id="vurl" target="_blank" href=""></a></div>
<div id="marker"></div>
<div id="playercontainer">
<div id="player"></div>
Expand Down
29 changes: 23 additions & 6 deletions styles.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
:root {
--w: 100%;
--formw: 800px;
--font-name: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
--byellow: #F38181;
Expand All @@ -20,7 +19,7 @@
body {
box-sizing: border-box;
padding: 0px;
width: var(--w);
width: 100%;
margin: 0;
padding: 0;
color: var(--textcolor);
Expand Down Expand Up @@ -334,6 +333,8 @@ form input {
left: 0;
background-color: lightgray;
font-size: 12px;
display: none;
padding: 4px 8px;
}

.selected {
Expand Down Expand Up @@ -454,10 +455,12 @@ figcaption {

footer {
width: 100%;
font-size: 0.9rem;
text-align: center;
position: sticky;
padding: 8px;
top: 100%;
opacity: 0.9;
}

.fixed {
Expand All @@ -468,7 +471,9 @@ footer {

@media (orientation: portrait) {
.fixed {
width: calc(100% - 32px) !important;
left: 0;
top: 0;
width: 100% !important;
}
.row {
display: block;
Expand Down Expand Up @@ -512,14 +517,18 @@ h2, h1 {
width: 320px;
}

#vurl {
font-size: 90%;
#vurl, #vduration {
font-size: 0.9rem;
}

code {
white-space: pre-wrap;
font-size: 1rem;
opacity: 0.8;
font-weight: 700;
}

#col2, #col3 {
padding-top: 80px;
}
@media print {
.btn, #tools, select {
Expand Down Expand Up @@ -551,3 +560,11 @@ code {
#marker {
height: 1px;
}

.plist {
margin: 0;
}

.bold {
font-weight: bolder;
}

0 comments on commit 7a6ff28

Please sign in to comment.