diff --git a/cps/static/js/reading/epub-progress.js b/cps/static/js/reading/epub-progress.js
new file mode 100644
index 00000000..985a9bb8
--- /dev/null
+++ b/cps/static/js/reading/epub-progress.js
@@ -0,0 +1,80 @@
+class EpubParser {
+ constructor(filesList) {
+ this.files = filesList;
+ this.parser = new DOMParser();
+ this.opfXml = this.getOPFXml();
+ }
+
+
+ getTextByteLength() {
+ let size = 0;
+ for (let key in y = Object.keys(this.files)) {
+ let file = this.files[y[key]];
+ if (file.name.endsWith("html")) {
+ size += file._data.uncompressedSize;
+ }
+ }
+ return size;
+ }
+
+ /**
+ * @param {string} filename name of the file in filelist
+ * @return {string} string representation of decompressed bytes
+ */
+ decompress(filename) {
+ return pako.inflate(this.files[filename]._data.compressedContent, {raw: true, to: "string"});
+ }
+
+ getOPFXml() {
+ let content = this.decompress("META-INF/container.xml");
+ let xml = this.parser.parseFromString(content, "text/xml");
+ let path = xml.getElementsByTagName("rootfile")[0].getAttribute("full-path");
+ this.opfDir = path.split("/").slice(0, -1).join("/");
+ return this.parser.parseFromString(this.decompress(path), "text/xml");
+ }
+
+
+ getSpine() {
+ return Array.from(this.opfXml.getElementsByTagName("spine")[0].children).map(node => node.getAttribute("idref"));
+ }
+
+ /**
+ resolves an idref in content.opf to its file
+ */
+ resolveIDref(idref) {
+ return this.opfXml.getElementById(idref).getAttribute("href");
+ }
+
+ /**
+ * returns absolute path from path relative to content.opf
+ * @param path
+ */
+ absPath(path) {
+ if (this.opfDir) {
+ return [this.opfDir, path].join("/");
+ } else {
+ return path;
+ }
+ }
+
+ /**
+ returns the sum of the bytesize of all html files that are located before it in the spine
+ @param {string} currentFile idref of the current file, also part of the CFI, e.g. here: #epubcfi(/6/2[titlepage]!/4/1:0) it would be "titlepage"
+ */
+ getPreviousFilesSize(currentFile) {
+ let bytesize = 0;
+ for (let file of this.getSpine()) {
+ if (file !== currentFile) {
+ let filepath = this.absPath(this.resolveIDref(currentFile));
+ //ignore non text files
+ if (filepath.endsWith("html")) {
+ bytesize += this.files[filepath]._data.uncompressedSize;
+ }
+ } else {
+ break
+ }
+ }
+ return bytesize;
+ }
+
+}
diff --git a/cps/templates/read.html b/cps/templates/read.html
index e687f7c8..1ebb5bba 100644
--- a/cps/templates/read.html
+++ b/cps/templates/read.html
@@ -153,6 +153,7 @@
+