Skip to content

Commit

Permalink
Audio player for PDF book #57
Browse files Browse the repository at this point in the history
  • Loading branch information
filimo committed Nov 28, 2019
1 parent 357fbd1 commit 16cf379
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 49 deletions.
6 changes: 6 additions & 0 deletions ReaderTranslator.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
F0562E0D2362025E0074ACF5 /* WikipediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0229BE02362021200F12F47 /* WikipediaView.swift */; };
F0562E0E2362026C0074ACF5 /* Wikipedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06D1C0D2361FFBC008A0C38 /* Wikipedia.swift */; };
F0562E0F2362026C0074ACF5 /* Wikipedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06D1C0D2361FFBC008A0C38 /* Wikipedia.swift */; };
F0586482238FB03900E6DDFA /* PdfToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0586481238FB03900E6DDFA /* PdfToolbarView.swift */; };
F0586483238FB03900E6DDFA /* PdfToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0586481238FB03900E6DDFA /* PdfToolbarView.swift */; };
F06DB0FF2344856300C2DE90 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0AA69D7232E978E007CC07B /* Store.swift */; };
F06DB1002344856300C2DE90 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0AA69D7232E978E007CC07B /* Store.swift */; };
F06DB1042344975E00C2DE90 /* StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06DB1032344975E00C2DE90 /* StackView.swift */; };
Expand Down Expand Up @@ -212,6 +214,7 @@
F04C8312236187D6003A25B4 /* Macmillan.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Macmillan.swift; sourceTree = "<group>"; };
F0505C522360D37C004F2D50 /* Longman.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Longman.swift; sourceTree = "<group>"; };
F0505C532360D3DA004F2D50 /* LongmanView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongmanView.swift; sourceTree = "<group>"; };
F0586481238FB03900E6DDFA /* PdfToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PdfToolbarView.swift; sourceTree = "<group>"; };
F062029423812264002EEAEE /* YTranslator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YTranslator.swift; sourceTree = "<group>"; };
F06D1C0D2361FFBC008A0C38 /* Wikipedia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wikipedia.swift; sourceTree = "<group>"; };
F06DB1032344975E00C2DE90 /* StackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -557,6 +560,7 @@
F0AB12A2233F5798005B9F2A /* ReaderView_PDF.swift */,
F0AB12A4233F57B3005B9F2A /* ReaderView_Web.swift */,
F026B1E72344830200E032B9 /* SafariView.swift */,
F0586481238FB03900E6DDFA /* PdfToolbarView.swift */,
);
path = Modes;
sourceTree = "<group>";
Expand Down Expand Up @@ -821,6 +825,7 @@
F0305FD42381271A002AC5F5 /* YTranslator.swift in Sources */,
F0EE0A172347BF09004A5EAD /* WKPageView.swift in Sources */,
F0C4EDA52349260000CCD97A /* ReversoView.swift in Sources */,
F0586483238FB03900E6DDFA /* PdfToolbarView.swift in Sources */,
F06DB10B234504FD00C2DE90 /* EditorNSTextRepresentable.swift in Sources */,
F0AD8B1C236413F60017C22F /* AvailableView.swift in Sources */,
F06DB10E23450B6000C2DE90 /* View.swift in Sources */,
Expand Down Expand Up @@ -905,6 +910,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F0586482238FB03900E6DDFA /* PdfToolbarView.swift in Sources */,
F0AB12A8233F5802005B9F2A /* StatusBarView_Tabs.swift in Sources */,
F0AB12B4233F599C005B9F2A /* StatusBarView_Voice_Favorite.swift in Sources */,
F0AA69A1232E9710007CC07B /* AppDelegate.swift in Sources */,
Expand Down
6 changes: 3 additions & 3 deletions ReaderTranslator/Components/OpenPanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class OpenPanel {
static func showChooseFileDialog(
title: String,
allowedFileTypes: [String],
onFinished: @escaping (_: String?) -> Void) {
onFinished: @escaping (_: URL?) -> Void) {

let openPanel = NSOpenPanel()

Expand All @@ -26,9 +26,9 @@ class OpenPanel {

openPanel.begin { result -> Void in
if result == .OK {
onFinished(openPanel.url?.absoluteString ?? "")
onFinished(openPanel.url)
} else {
onFinished("")
onFinished(nil)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ struct PDFKitView: View {
}

private func start() {
self.store.$currentPage
self.store.$currentPdfPage
.debounce(for: 0.5, scheduler: RunLoop.main)
.removeDuplicates()
.sink { page in
Expand All @@ -79,7 +79,7 @@ struct PDFKitView: View {
.receive(on: RunLoop.main)
.sink { mode in
if mode == .pdf {
if let page = Int(self.store.currentPage) {
if let page = Int(self.store.currentPdfPage) {
print("debug: ", "willViewModeChanged: ", page)
self.goCurrentPage(page: page)
}
Expand Down Expand Up @@ -116,7 +116,7 @@ struct PDFKitView: View {
let page = document.index(for: currentPage)

print("debug: ", "PDFViewPageChanged: ", page + 1, document.pageCount)
self.store.currentPage = String(page + 1)
self.store.currentPdfPage = String(page + 1)
self.store.lastPdfPage = String(page + 1)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
if(selection.focusNode.id == 'search-input') return

if(selection.toString().trim()) {
sendIn1000('selectionchange', 'document', event)
send('selectionchange', 'document', event)
}
})

Expand Down Expand Up @@ -387,11 +387,11 @@
if(location.hostname == "localhost" && location.pathname.includes('audiobooks')) { } else { return }

var $time = document.createElement('input')
$time.style.cssText = 'position:fixed;width:100px;top:0;left:0'
$time.style.cssText = 'position:fixed;width:50px;top:0;left:0'
$time.value = "0"
document.body.appendChild($time)

let audio = new Audio("../audiobook.m4a")
let audio = new Audio(localStorage.getItem('audio_file'))

audio.oncanplay = function() {
audio.currentTime = localStorage.getItem('currentTime')
Expand All @@ -404,8 +404,27 @@
function init() {
[...document.querySelectorAll('p')].forEach(item=>{
let html = (item.textContent.match(/[^\.!\?]+[\.!\?]+/g) || [])
.map(item=>`<span class="sentence">${item.trim()}</span>`)
.map(item=>{
let text = item.trim()
let time = localStorage.getItem(text)

if(time) {
return `<span class="sentence" time=${time}>${text}</span>`
}else{
return `<span class="sentence">${text}</span>`
}
})
.join('\n')
if(html == "") {
let text = item.textContent.trim()
let time = localStorage.getItem(text)

if(time) {
html = `<span class="sentence" time=${time}>${text}</span>`
}else{
html = `<span class="sentence">${text}</span>`
}
}
item.innerHTML = html
})
let lastSentence = localStorage.getItem('lastSentence')
Expand All @@ -415,13 +434,12 @@

if(elm) {
elm.scrollIntoViewIfNeeded()
elm.style.backgroundColor = 'lightgrey'
}
}

var style=document.createElement('style')
style.type='text/css'
style.appendChild(document.createTextNode('.sentence:hover { background-color: yellow; background-color: yellow !important; }'))
style.appendChild(document.createTextNode('[time] { background-color: lightgrey; }\n .sentence:hover { background-color: yellow; background-color: yellow !important; }'))
document.getElementsByTagName('head')[0].appendChild(style)

// document.addEventListener('dblclick', event => {
Expand All @@ -444,22 +462,21 @@
let time = elm.getAttribute('time')
if(time) {
audio.currentTime = time
translateWithoutSpeaking(elm.textContent)
if(audio.paused) {
send('play', 'video', event, '')
audio.play()
}else{
audio.pause()
}
}else{
audio.pause()
localStorage.setItem('lastSentence', elm.textContent)
elm.style.backgroundColor="lightgrey"
elm.setAttribute('time', audio.currentTime)
localStorage.setItem(elm.textContent.trim(), audio.currentTime)
translateWithoutSpeaking(elm.textContent)
return
}

if(audio.paused) {
send('play', 'video', event, '')
audio.play()
}else{
audio.pause()
translateWithoutSpeaking(elm.textContent)
}
}
})
}
Expand Down
22 changes: 22 additions & 0 deletions ReaderTranslator/Extentions/CMTime.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// CMTime.swift
// ReaderTranslator
//
// Created by Viktor Kushnerov on 28/11/19.
// Copyright © 2019 Viktor Kushnerov. All rights reserved.
//

import Foundation

extension CMTime {
static func + (lhs: CMTime, rhs: TimeInterval) -> CMTime {
return CMTime(seconds: lhs.seconds + rhs,
preferredTimescale: lhs.timescale)
}

static func += (lhs: inout CMTime, rhs: TimeInterval) {
lhs = CMTime(seconds: lhs.seconds + rhs,
preferredTimescale: lhs.timescale)
}

}
4 changes: 2 additions & 2 deletions ReaderTranslator/Stores/Store.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Store: ObservableObject {

@Published(key: "enabledViews") var enabledViews: Set<AvailableView> = [.reverso, .gTranslator]

@Published var currentPage = "1"
@Published var currentPdfPage = "1"
@Published var pageCount = 0

@Published(key: "currentTab") var currentTab = 0 {
Expand All @@ -42,7 +42,7 @@ class Store: ObservableObject {
@Published
var lastWebPage = "" { willSet { self.savedLastWebPage[self.currentTab] = newValue } }

var lastPdf: String = ""
@Published(key: "lastPdf") var lastPdf: String = ""
@Published(key: "lastPdfPage") var lastPdfPage = "1"

@Published(key: "zoom") var zoom: CGFloat = 1
Expand Down
95 changes: 95 additions & 0 deletions ReaderTranslator/Views/ReaderView/Modes/PdfToolbarView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//
// AudioPlayerView.swift
// ReaderTranslator
//
// Created by Viktor Kushnerov on 28/11/19.
// Copyright © 2019 Viktor Kushnerov. All rights reserved.
//

import SwiftUI
import AVFoundation

private var player: AVAudioPlayer?

struct PdfToolbarView: View {
@ObservedObject var store = Store.shared

@State var currentStatus = ""
@State var isPlaying = false
@State var audioRate: Float = 1 {
didSet {
player?.rate = audioRate
}
}

var body: some View {
HStack {
Button(
action: {
OpenPanel.showChooseFileDialog(title: "Open PDF file", allowedFileTypes: ["pdf"]) { url in
guard let url = url?.absoluteString else { return }

self.store.lastPdfPage = "1"
self.store.lastPdf = url
}
},
label: { Text("Open PDF") })

Button(action: {
OpenPanel.showChooseFileDialog(title: "Open audio file", allowedFileTypes: ["mp3", "mov"]) { url in
guard let url = url else { return }
do {
player = try AVAudioPlayer(contentsOf: url)
player?.enableRate = true
} catch {
print(error)
}
}
}, label: { Text("Open audio") })

Group {
Button(action: { player?.currentTime = 0 }, label: { Text("|<") })
Button(action: { player?.currentTime -= 100 }, label: { Text("-100") })
Button(action: { player?.currentTime -= 10 }, label: { Text("-10") })
Button(action: { player?.currentTime -= 5 }, label: { Text("-5") })
Button(action: { player?.currentTime -= 1 }, label: { Text("-1") })
}

Button(action: {
if self.isPlaying { player?.pause() } else { player?.play() }
}, label: { Text(isPlaying ? "Pause" : "Play") })

Group {
Button(action: { player?.currentTime += 1 }, label: { Text("+1") })
Button(action: { player?.currentTime += 5 }, label: { Text("+5") })
Button(action: { player?.currentTime += 10 }, label: { Text("+10") })
Button(action: { player?.currentTime += 100 }, label: { Text("+100") })
}

Group {
Divider()
Button(action: { self.audioRate -= 0.1 }, label: { Text("-") })
Text(String(format: "%.1f", arguments: [audioRate]))
Button(action: { self.audioRate += 0.1 }, label: { Text("+") })
}

Group {
Divider()
Text("\(currentStatus)")
}
}
.onAppear {
_ = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { _ in
guard let player = player else { return }
self.currentStatus = String(format: "%.1f/%.1f", player.currentTime, player.duration)
self.isPlaying = player.isPlaying
}
}
}
}

struct AudioPlayerView_Previews: PreviewProvider {
static var previews: some View {
PdfToolbarView()
}
}
3 changes: 2 additions & 1 deletion ReaderTranslator/Views/ReaderView/Modes/ReaderView_PDF.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ struct ReaderView_PDF: View {
@ObservedObject var store = Store.shared

var body: some View {
Group {
VStack {
if store.viewMode == .pdf {
PDFKitView()
PdfToolbarView().frame(height: 30)
}
}
}
Expand Down
21 changes: 0 additions & 21 deletions ReaderTranslator/Views/StatusBarView/StatusBarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ struct StatusBarView: View {
StatusBarView_Safari()
StatusBarView_Bookmarks()
StatusBarView_ViewsEnabler()
openPDFPanelView
// gTranslatorNavbarView
speechHandler
playbackRateView
Expand All @@ -50,26 +49,6 @@ struct StatusBarView: View {
}
}

private var openPDFPanelView: some View {
Group {
if store.viewMode == .pdf {
Spacer()
Button(
action: {
OpenPanel.showChooseFileDialog(title: "Open PDF file", allowedFileTypes: ["pdf"]) { urlString in
guard let url = urlString else { return }

self.store.lastPdfPage = "1"
self.store.lastPdf = url
}
},
label: { Text("Open file") })
} else {
EmptyView()
}
}
}

private var gTranslatorNavbarView: some View {
Group {
Spacer()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ struct StatusBarView_PdfPage: View {
Divider().fixedSize()
Text("Page:")
#if os(macOS)
TextField(" ", text: self.$store.currentPage)
TextField(" ", text: self.$store.currentPdfPage)
.fixedSize()
.textFieldStyle(RoundedBorderTextFieldStyle())
#else
TextField(" ", text: self.$store.currentPage)
TextField(" ", text: self.$store.currentPdfPage)
.fixedSize()
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.numberPad)
Expand Down
Loading

0 comments on commit 16cf379

Please sign in to comment.