-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.js
280 lines (259 loc) · 11.5 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
// DOMContentLoaded is fired once the document has been loaded and parsed,
// but without waiting for other external resources to load (css/images/etc)
// That makes the app more responsive and perceived as faster.
// https://developer.mozilla.org/Web/Reference/Events/DOMContentLoaded
window.addEventListener('DOMContentLoaded', function() {
// We'll ask the browser to use strict code to help us catch errors earlier.
// https://developer.mozilla.org/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode
'use strict';
var translate = navigator.mozL10n.get;
var hasLoaded = localStorage.getItem("default");
if(Boolean(localStorage.getItem("default")) != true){
localStorage.setItem("default", "true"); // Set default settings
localStorage.setItem("directoryCreated", "false");
}
// if(hasLoaded == null || Boolean(hasLoaded) != true){
// localStorage.setItem("default", "true");
// }
// else {
// Load book
// window.location = "book.html";
// }
});
// Bugs:
// -Not loading when spaces are used
// -Not working with multiple pages
// -Search results aren't resetting
// -Slider not refreshing on page view
// ------- TODO LIST -------
// Set audioManager SRC to downloaded file, also add delete buttons to listView --
// Delete is the .delete function of the DeviceStorage API
// Add directories for each book, show downloaded files as a list of directories
var bookCache = {};
// get data after ? in url, such as 45 from '/chapters.html?45' (there's most likely a more elegant solution than this for passing variables between pagecreate events)
function bookIDFromUrlAttribute(target) {
var data_url = target.attributes['data-url'].value;
var data = data_url.substring(data_url.lastIndexOf('?') + 1);
console.log(data);
return data;
}
$( document ).on( "pagecreate", "#chaptersListPage", function( event ) {
// $("#audioTime").attr("max", parseInt(timesecs)).slider("refresh");
var currBook = bookCache[bookIDFromUrlAttribute(event.target)];
if (!currBook) { // currBook is undefined if you refresh the app from WebIDE on a chapter list page
console.warn("Chapters List: currBook was undefined, which freezes the app. Did you refresh from WebIDE?");
return false;
}
var generate_chapter_list_item = function (chapter) { // is this good coding practice? local method defined inside method
var chapterListItem = $('<li chapter-id=' + chapter.index + '><a href="book.html"><h2>' + chapter.title + '</h2></a></li>');
chapterListItem.click(function (){
chapter_index = $(this).attr("chapter-id");
localStorage.setItem("index", chapter_index); // Still uses localstorage, needs to be updated.
});
$("#chaptersList").append(chapterListItem);
}
if (currBook.chapters != null) {
console.log('currBook.chapters was not null');
$.each(currBook.chapters, function(index, chapter) {
generate_chapter_list_item(chapter);
$("#chaptersList").listview('refresh');
});
} else {
console.log('currBook.chapters was null');
getXML("https://librivox.org/rss/" + encodeURIComponent(currBook.id), function(xhr) { // get streaming urls from book's rss page
var xml = $(xhr.response),
titles = xml.find("title"),
chapters = [];
titles.each(function(index, element) {
var chapter = new Chapter({'index': index, 'title': element.text, 'tag': element})
chapters.push(chapter);
generate_chapter_list_item(chapter);
});
currBook.chapters = chapters;
$("#chaptersList").listview('refresh');
});
}
});
function Book(args) {
this.chapters = args.chapters
var json = args.json;
this.json = json;
this.description = json.description;
this.title = json.title;
this.id = json.id;
}
function Chapter(args) {
title_regex = /^<!\[CDATA\[(.*)\]\]>$/;
title_match = title_regex.exec(args.title);
this.title = title_match[1] ? title_match[1] : args.title; // if regex doesn't match, fall back to raw string
this.tag = $(args.tag);
this.index = args.index;
}
// TODO refactor this method (it's the copy and paste version of that other method :P)
$( document ).on( "pagecreate", "#homeBook", function( event ){
$(".ui-slider-input").hide();
$(".ui-slider-handle").hide();
$("#downloadProgress").val(0).slider("refresh");
$("#downloadFullBook").click(function(){
var URL = localStorage.getItem("download");
downloadBook(URL);
});
$("#downloadPart").click(function(){
var URL = localStorage.getItem("bookURL");
downloadBook(URL);
});
var currIndex = localStorage.getItem("index");
var id = localStorage.getItem("id");
getJSON("https://librivox.org/api/feed/audiobooks/id/" + encodeURIComponent(id) + "?&format=json", function(xhr){
var book = xhr.response.books[0];
var timesecs = xhr.response.books[0].totaltimesecs;
var time = xhr.response.books[0].totaltime;
$("#audioTime").attr("max", parseInt(timesecs)).slider("refresh");
// -- Initialize Get RSS --
getXML("https://librivox.org/rss/" + encodeURIComponent(id), function(xhr){
var xml = $(xhr.response);
var title = xml.find( "title" ); // This is the "official" chapter title
var bookTitle = localStorage.getItem("title");
var enclosure = xml.find("enclosure");
var currTitle = title[currIndex].innerHTML.replace("<![CDATA[", "").replace("]]>", "");
var currEnclosure = enclosure[currIndex];
var url = $(currEnclosure).attr("url");// We no longer need to loop through enclosures or the index, we have that now!
localStorage.setItem("bookURL", url);
console.log("You are trying to read " + bookTitle + ": " + currTitle + " on chapter " + currIndex + " with URL " + url);
console.log("Loading Audio!");
$("#audioSource").prop('type', "audio/mpeg");
$("#audioSource").prop("src", url);
$("#audioSource").trigger('load');
});
});
});
$( document ).on( "pagecreate", "#homeFileManager", function(){ // TODO work only in LibriFox directory
var sdcard = navigator.getDeviceStorage('sdcard');
var request = sdcard.enumerate();
request.onsuccess = function(){
if(this.result){ // Todo list isn't determining different list items
fileListItem = $('<li><a data-icon="delete">' + this.result.name + '</a></li>');
// Options and menus to display info?
//<select data-native-menu="false" name="fileSelect"><option data-placeholder="true" value="main-name">Name of file</option></select>
fileListItem.click(function(){
console.log("You clicked on " + $(this).text());
});
fileListItem.on("taphold", function(){
console.log("Taphold on " + $(this).text());
// Open up menu to save, rename, delete
})
$("#downloadedFiles").append(fileListItem);
this.continue();
};
$("#downloadedFiles").listview('refresh');
};
request.onerror = function(){
console.log("No data found on SDCard!");
$("#noAvailableDownloads").show();
}
});
$("#audioSource").on("timeupdate", function(){ // On audio change, save new time to localSettings
var floatSeconds = $("#audioSource").prop('currentTime');
var hours = +localStorage.getItem("hours");
var minutes = +localStorage.getItem("minutes");
var seconds = +localStorage.getItem("seconds");
console.log(hours + ":" + minutes + ":" + seconds);
var fullSeconds = (hours * 3600) + (minutes * 60) + seconds;
console.log(floatSeconds <= 5);
console.log(fullSeconds + " and " + (fullSeconds >= 5));
if((floatSeconds <= 5) && (fullSeconds >= 5)){
$("#audioSource").prop('currentTime', fullSeconds);
}
else {
var intSeconds = Math.floor(floatSeconds);
console.log("Floatseconds is currently " + floatSeconds);
var hours = Math.floor(intSeconds / 3600);
intSeconds -= hours * 3600;
var minutes = Math.floor(intSeconds / 60);
intSeconds -= minutes * 60;
localStorage.setItem("hours", hours);
localStorage.setItem("minutes", minutes);
localStorage.setItem("seconds", intSeconds);
}
});
$("#play").click(function(){
$("#audioSource").trigger('play');
});
$("#pause").click(function(){
$("#audioSource").trigger('pause');
});
$("#stop").click(function(){
$("#audioSource").trigger('stop');
});
$("#volumeSlider").change(function(){
writeToSettings("volume", $("#volumeSlider").slider("value").val());
});
function downloadBook(URL) {
var id = localStorage.getItem("id");
console.log("URL determined to be " + URL);
var sdcard = navigator.getDeviceStorage("sdcard");
// var download = $.get(URL);
var progress_callback = function (event) {
if(event.lengthComputable){
var percentage = (event.loaded / event.total) * 100;
$("#downloadProgress").val(percentage).slider('refresh');
console.log("Downloading... " + percentage + "%");
}
}
getBlob(URL, function(xhr) {
var filename = URL.substring(URL.lastIndexOf('/')+1);
sdcard.addNamed(xhr.response, filename);
}, {'progress_callback': progress_callback});
}
$("#newSearch").submit(function(event){
$("#booksList").empty(); // empty the list of any results from previous searches
var input = $("#bookSearch").val();
getJSON("https://librivox.org/api/feed/audiobooks/title/^" + encodeURIComponent(input) + "?&format=json",function(xhr) {
if(typeof (xhr.response.books) === 'undefined'){
// Show "No Available Books" text! Try making your search simpler.
$("#noAvailableBooks").show();
}
else {
console.log("librivox responded with " + xhr.response.books.length + " book(s) and status " + xhr.status);
xhr.response.books.forEach(function(entry) {
var book = new Book({'json': entry});
bookCache[book.id] = book; // this ends up storing id 3 times (as key, in book object, and in book object json), which is a little bit icky
bookListItem = $('<li><a href="chapters.html?'+ book.id + '"><h2>' + book.title + '</h2><p>' + book.description + '</p></a></li>');
$("#booksList").append(bookListItem);
});
}
$("#booksList").listview('refresh');
});
return false; // cancels form event
});
function getDataFromUrl(url, type, load_callback, other_args) // NEEDS MORE MAGIC STRINGS
{
other_args = other_args || {};
var xhr = new XMLHttpRequest({ mozSystem: true });
if (xhr.overrideMimeType && type == 'json') {
xhr.overrideMimeType('application/json');
}
other_args.error_callback = other_args.error_callback || function(e) {
console.log("error loading json from url " + url);
console.log(e);
}
other_args.timeout_callback = other_args.timeout_callback || function(e) {
console.log("timeout loading json from url " + url);
console.log(e);
}
xhr.addEventListener('load', function(e) {
load_callback(xhr,e);
});
xhr.addEventListener('error', other_args.error_callback);
xhr.addEventListener('timeout', other_args.timeout_callback);
xhr.addEventListener('progress', other_args.progress_callback);
// xhr.upload.addEventListener("load", transferComplete, false);
// xhr.upload.addEventListener("error", transferFailed, false);
// xhr.upload.addEventListener("abort", transferCanceled, false);
xhr.open('GET', url);
if (type != 'default') { xhr.responseType = type; }
xhr.send();
}
function getJSON(url, load_callback, other_args) { getDataFromUrl(url, 'json', load_callback, other_args); }
function getXML(url, load_callback, other_args) { getDataFromUrl(url, 'default', load_callback, other_args); }
function getBlob(url, load_callback, other_args) { getDataFromUrl(url, 'blob', load_callback, other_args); }