index.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. <?php
  2. if (!file_exists("config.php")) {
  3. die("Please copy config.php-dist to config.php and edit it.");
  4. }
  5. if (!is_writable("sessions")) {
  6. die("sessions/ directory is not writable.");
  7. }
  8. if (isset($_SERVER["PHP_AUTH_USER"])) {
  9. die("HTTP Authentication is no longer supported, please see migration notes in git.");
  10. }
  11. if (!isset($_COOKIE['epube_sid'])) {
  12. header("Location: login.php");
  13. exit;
  14. }
  15. require_once "config.php";
  16. require_once "sessions.php";
  17. require_once "db.php";
  18. @$owner = SQLite3::escapeString($_SESSION["owner"]);
  19. if (!$owner) {
  20. header("Location: login.php");
  21. exit;
  22. }
  23. if (basename(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)) != 'index.php') {
  24. header('Location: index.php');
  25. exit;
  26. }
  27. if (!$owner) {
  28. header($_SERVER["SERVER_PROTOCOL"]." 401 Unauthorized");
  29. echo "Unauthorized";
  30. die;
  31. }
  32. if (!is_writable(SCRATCH_DB)) {
  33. die(SCRATCH_DB . " is not writable");
  34. }
  35. if (!is_writable(dirname(SCRATCH_DB))) {
  36. die(dirname(SCRATCH_DB) . " directory is not writable");
  37. }
  38. @$mode = htmlspecialchars($_REQUEST["mode"]);
  39. $ldb = Db::get();
  40. ?>
  41. <!DOCTYPE html>
  42. <html>
  43. <head>
  44. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  45. <link href="lib/bootstrap/v3/css/bootstrap.min.css" rel="stylesheet" media="screen">
  46. <link href="lib/bootstrap/v3/css/bootstrap-theme.min.css" rel="stylesheet" media="screen">
  47. <link href="lib/qtip2/jquery.qtip.min.css" rel="stylesheet" media="screen">
  48. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  49. <script src="lib/bootstrap/v3/js/jquery.js"></script>
  50. <script src="lib/bootstrap/v3/js/bootstrap.min.js"></script>
  51. <script src="lib/holder.min.js"></script>
  52. <script src="lib/localforage.min.js"></script>
  53. <script src="lib/qtip2/jquery.qtip.min.js"></script>
  54. <title>The Epube</title>
  55. <link type="text/css" rel="stylesheet" media="screen" href="css/index.css" />
  56. <link rel="shortcut icon" type="image/png" href="img/favicon.png" />
  57. <link rel="icon" sizes="192x192" href="img/favicon_hires.png">
  58. <link rel="manifest" href="manifest.json">
  59. <meta name="mobile-web-app-capable" content="yes">
  60. <script src="js/index.js"></script>
  61. <script src="js/common.js"></script>
  62. </head>
  63. <body>
  64. <?php
  65. @$query = $_REQUEST["query"];
  66. ?>
  67. <div class="navbar navbar-default navbar-static-top">
  68. <div class="container">
  69. <div class="navbar-header">
  70. <span class="navbar-brand"><a href="?">The Epube</a></span>
  71. <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#nav-collapse" aria-expanded="false">
  72. <span class="sr-only">Toggle navigation</span>
  73. <span class="icon-bar"></span>
  74. <span class="icon-bar"></span>
  75. <span class="icon-bar"></span>
  76. </button>
  77. </div>
  78. <?php
  79. $fav_active = $mode == "favorites" ? "active" : "";
  80. $index_active = $mode != "favorites" ? "active" : "";
  81. ?>
  82. <div class="collapse navbar-collapse" id="nav-collapse">
  83. <ul class="nav navbar-nav">
  84. <li class="<?php echo $index_active ?>"><a href="index.php">All</a></li>
  85. <li class="<?php echo $fav_active ?>"><a href="index.php?mode=favorites">Favorites</a></li>
  86. <li><a href="offline.html">Local</a></li>
  87. </ul>
  88. <?php if ($mode == "favorites") { ?>
  89. <form onsubmit="return false;" class="navbar-form navbar-right">
  90. <button type="submit" onclick="offline_get_all()" class="btn btn-primary">Get all</button>
  91. </form>
  92. <?php } ?>
  93. <form class="navbar-form navbar-right">
  94. <input type="text" name="query" class="form-control"
  95. value="<?php echo htmlspecialchars($query) ?>">
  96. <input type="hidden" name="mode" value="<?php echo $mode ?>">
  97. <button type="submit" class="btn btn-default">Search</button>
  98. </form>
  99. <?php if ($mode != "favorites") { ?>
  100. <ul class="nav navbar-nav navbar-right">
  101. <li><a href="logout.php">Logout</a></li>
  102. </li>
  103. <?php } ?>
  104. </div>
  105. </div>
  106. </div>
  107. <script type="text/javascript">
  108. var index_mode = "<?php echo $mode ?>";
  109. $(document).ready(function() {
  110. if ('serviceWorker' in navigator) {
  111. navigator.serviceWorker
  112. .register('worker.js')
  113. .then(function() {
  114. console.log("service worker registered");
  115. });
  116. navigator.serviceWorker.addEventListener('message', function(event) {
  117. // not used yet
  118. if (event.data == 'client-reload') {
  119. window.location.reload();
  120. }
  121. });
  122. }
  123. mark_offline_books();
  124. cache_refresh();
  125. init_tooltips();
  126. });
  127. </script>
  128. <div class="container">
  129. <div class="modal fade" id="summary-modal" tabindex="-1" role="dialog">
  130. <div class="modal-dialog" role="document">
  131. <div class="modal-content">
  132. <div class="modal-header">
  133. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  134. <h4 class="modal-title">Summary</h4>
  135. </div>
  136. <div class="modal-body">
  137. <div class="book-summary"> </div>
  138. </div>
  139. <div class="modal-footer">
  140. <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
  141. </div>
  142. </div>
  143. </div>
  144. </div>
  145. <?php
  146. require_once "config.php";
  147. $db = new SQLite3(CALIBRE_DB, SQLITE3_OPEN_READONLY);
  148. if ($query) {
  149. $query_esc = SQLite3::escapeString($query);
  150. $search_qpart = "(LOWER(books.author_sort) LIKE LOWER('%$query_esc%') OR
  151. LOWER(books.title) LIKE LOWER('%$query_esc%') OR
  152. LOWER(series_name) LIKE LOWER('%$query_esc%'))";
  153. } else {
  154. $search_qpart = "1";
  155. }
  156. $ids_qpart = "1";
  157. if ($mode == "favorites") {
  158. $fav_result = $ldb->query("SELECT bookid FROM epube_favorites WHERE owner = '$owner'");
  159. $fav_ids = [];
  160. while ($line = $fav_result->fetchArray(SQLITE3_ASSOC)) {
  161. array_push($fav_ids, $line["bookid"]);
  162. }
  163. $ids_qpart = "books.id IN (" . implode(",", $fav_ids) . ")";
  164. }
  165. $limit = 60;
  166. @$offset = (int) $_REQUEST["offset"];
  167. $order_by = $query ? "author_sort, series_name, series_index, title, books.id" : "books.id DESC";
  168. $result = $db->query("SELECT books.*, s.name AS series_name,
  169. (SELECT id FROM data WHERE book = books.id AND format = 'EPUB' LIMIT 1) AS epub_id FROM books
  170. LEFT JOIN books_series_link AS bsl ON (bsl.book = books.id)
  171. LEFT JOIN series AS s ON (bsl.series = s.id)
  172. WHERE $search_qpart AND $ids_qpart ORDER BY $order_by LIMIT $limit OFFSET $offset");
  173. print "<div class='row'>";
  174. $rows = 0;
  175. while ($line = $result->fetchArray(SQLITE3_ASSOC)) {
  176. ++$rows;
  177. $cover_link = "backend.php?" . http_build_query(["op" => "cover", "id" => $line["id"]]);
  178. $author_link = "?" . http_build_query(["query" => $line["author_sort"]]);
  179. $in_progress = false;
  180. $is_read = false;
  181. if ($line["epub_id"]) {
  182. $read_link = "read.html?" . http_build_query(["id" => $line["epub_id"], "b" => $line["id"]]);
  183. $lastread_result = $ldb->query("SELECT lastread, total_pages FROM epube_books, epube_pagination
  184. WHERE epube_pagination.bookid = epube_books.bookid AND
  185. epube_books.bookid = " . $line["epub_id"] . " AND owner = '$owner'");
  186. if ($lastread_line = $lastread_result->fetchArray(SQLITE3_ASSOC)) {
  187. $lastread = $lastread_line["lastread"];
  188. $total_pages = $lastread_line["total_pages"];
  189. $is_read = $total_pages - $lastread < 5;
  190. $in_progress = $lastread > 1;
  191. }
  192. } else {
  193. $read_link = "";
  194. }
  195. $cover_read = $is_read ? "read" : "";
  196. print "<div class='col-xs-6 col-sm-3 col-md-2 index_cell' id=\"cell-".$line["id"]."\">";
  197. print "<div class=\"thumb $cover_read\">";
  198. if ($read_link) print "<a href=\"$read_link\">";
  199. if ($line["has_cover"]) {
  200. print "<img data-book-id='".$line["id"]."' src='$cover_link'>";
  201. } else {
  202. print "<img data-book-id='".$line["id"]."' data-src='holder.js/120x180'>";
  203. }
  204. if ($read_link) print "</a>";
  205. print "<div class='caption'>";
  206. $title_class = $in_progress ? "in_progress" : "";
  207. print "<div title=\"".htmlspecialchars($line["title"])."\" class=\"$title_class\">";
  208. if ($read_link) {
  209. print "<a href=\"$read_link\">" . $line["title"] . "</a>";
  210. } else {
  211. print $line["title"];
  212. }
  213. print "</div>";
  214. if ($line["series_name"]) {
  215. $series_link = "?" . http_build_query(["query" => $line["series_name"]]);
  216. $series_full = $line["series_name"] . " [" . $line["series_index"] . "]";
  217. print "<div><a title=\"".htmlspecialchars($series_full)."\"
  218. href=\"$series_link\">$series_full</a></div>";
  219. }
  220. print "<div><a title=\"".htmlspecialchars($line["author_sort"])."\"
  221. href=\"$author_link\">" . $line["author_sort"] . "</a></div>";
  222. $data_result = $db->query("SELECT * FROM data WHERE book = " . $line["id"] . " LIMIT 3");
  223. /*print "<span class=\"label label-default\">
  224. <span class=\"glyphicon glyphicon-download-alt\">
  225. </span>";*/
  226. print "</div>";
  227. ?>
  228. <div class="dropdown" style="white-space : nowrap">
  229. <a href="#" data-toggle="dropdown" role="button">
  230. More...
  231. <span class="caret"></span>
  232. </a>
  233. <ul class="dropdown-menu" aria-labelledby="dLabel">
  234. <!-- <?php if ($line["series_name"]) {
  235. $series_link = "?" . http_build_query(["query" => $line["series_name"]]);
  236. $series_full = $line["series_name"] . " [" . $line["series_index"] . "]";
  237. print "<li><a title=\"".htmlspecialchars($series_full)."\"
  238. href=\"$series_link\">$series_full</a></li>";
  239. }
  240. ?> -->
  241. <?php
  242. $fav_result = $ldb->query("SELECT id FROM epube_favorites WHERE bookid = ".
  243. $line['id'] . " AND owner = '$owner' LIMIT 1");
  244. $found_id = false;
  245. while ($fav_line = $fav_result->fetchArray(SQLITE3_ASSOC)) {
  246. $found_id = $fav_line["id"];
  247. }
  248. if ($found_id) {
  249. $toggle_fav_prompt = "Remove from favorites";
  250. $fav_attr = "1";
  251. } else {
  252. $toggle_fav_prompt = "Add to favorites";
  253. $fav_attr = "0";
  254. }
  255. ?>
  256. <li><a href="#" onclick="return show_summary(this)"
  257. data-book-id="<?php echo $line["id"] ?>">Summary</a></li>
  258. <li><a href="#" onclick="return toggle_fav(this)"
  259. data-is-fav="<?php echo $fav_attr ?>"
  260. class="fav_item" data-book-id="<?php echo $line["id"] ?>">
  261. <?php echo $toggle_fav_prompt ?></a></li>
  262. <?php if ($line["epub_id"]) { ?>
  263. <li><a href="#" onclick=""
  264. data-book-id="<?php echo $line["id"] ?>" class="offline_dropitem"></a></li>
  265. <li class="divider"></li>
  266. <?php } ?>
  267. <?php while ($data_line = $data_result->fetchArray(SQLITE3_ASSOC)) {
  268. if ($data_line["format"] != "ORIGINAL_EPUB") {
  269. $label_class = $data_line["format"] == "EPUB" ? "label-success" : "label-primary";
  270. $download_link = "backend.php?op=download&id=" . $data_line["id"];
  271. print "<li><a target=\"_blank\" href=\"$download_link\">Download: <span class=\"label $label_class\">" .
  272. $data_line["format"] . "</span></a></li>";
  273. }
  274. } ?>
  275. </ul>
  276. </div>
  277. <?php
  278. print "</div>";
  279. print "</div>";
  280. }
  281. ?>
  282. </div>
  283. <?php
  284. $prev_link = http_build_query(["mode" => $mode, "query" => $query, "offset" => $offset - $limit]);
  285. $next_link = http_build_query(["mode" => $mode, "query" => $query, "offset" => $offset + $limit]);
  286. ?>
  287. <ul class="pager">
  288. <?php if ($offset > 0) { ?>
  289. <li class="previous"><a href="?<?php echo $prev_link ?>">&larr; Previous</a></li>
  290. <?php } else { ?>
  291. <li class="previous disabled"><a href="#">&larr; Previous</a></li>
  292. <?php } ?>
  293. <?php if ($rows == $limit) { ?>
  294. <li class="next"><a href="?<?php echo $next_link ?>">Next&rarr;</a></li>
  295. <?php } else { ?>
  296. <li class="next disabled"><a href="#">Next&rarr;</a></li>
  297. <?php } ?>
  298. </ul>
  299. <p class="text-center small">
  300. <a class="text-muted" href="#" onclick="return cache_refresh(true)">Refresh cache</a>
  301. </p>
  302. </div>
  303. </body>
  304. </html>