Add password-less page with searches
authorJoey Schulze <joey@infodrom.org>
Sun, 23 Dec 2018 21:33:46 +0000 (22:33 +0100)
committerJoey Schulze <joey@infodrom.org>
Tue, 25 Dec 2018 09:16:08 +0000 (10:16 +0100)
class/ajax.class.php
class/cache.class.php [new file with mode: 0644]
class/config.class.php
html/index.php [new file with mode: 0644]
html/main.js [new file with mode: 0644]
html/musiikki.css
templates/main.phtml [new file with mode: 0644]
templates/main_home.phtml [new file with mode: 0644]
templates/results.phtml [new file with mode: 0644]
templates/search.phtml [new file with mode: 0644]

index 2c873ef..8d11ee5 100644 (file)
@@ -136,4 +136,24 @@ class AJAX {
 
        return false;
     }
+
+    public static function getsearchAction()
+    {
+       return array();
+    }
+
+    public static function searchAction()
+    {
+       $cache = new Cache();
+
+       $list = $cache->findTitles($_POST['keyword']);
+
+       return $list;
+    }
+
+    public static function getresultsAction()
+    {
+       return array();
+    }
+
 }
diff --git a/class/cache.class.php b/class/cache.class.php
new file mode 100644 (file)
index 0000000..9cd885a
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+class Cache {
+    public function __construct()
+    {
+       $cache = Config::main()->get('cache');
+
+       if (is_null($cache))
+           throw new Exception('Cache file not found');
+
+       $this->db = new PDO('sqlite:/'.$cache);
+    }
+
+    public function findTitles($keyword)
+    {
+       $media_dir = Config::main()->get('media_dir_A');
+       $results = array('count' => 0, 'list' => []);
+       $sql = sprintf("SELECT path, title, timestamp, size FROM details WHERE path LIKE %s AND mime IS NOT NULL",
+                      $this->db->quote('%'.$keyword.'%'));
+
+       $sth = $this->db->query($sql);
+       if ($sth === false) return $results;
+
+       $seen = [];
+       while ($row = $sth->fetchObject()) {
+           $id = "{$row->TIMESTAMP}-{$row->SIZE}";
+           if (!array_key_exists($id, $seen)) {
+               $results['count']++;
+               $seen[$id] = true;
+           }
+           $section = '[empty]';
+           $path = substr($row->PATH, strlen($media_dir)+1);
+
+            if (($pos = strrpos($path, '.')) > strlen($path)-10)
+               $path = substr($path, 0, $pos);
+
+           if (($pos = strpos($path, '/')) < 20) {
+               $section = substr($path, 0, $pos);
+               $path = substr($path, $pos+1);
+           }
+
+           if (!array_key_exists($section, $results['list']))
+               $results['list'][$section] = [];
+           $results['list'][$section][] = ['path' => dirname($path), 'name' => basename($path), 'title' => $row->TITLE];
+       }
+
+       return $results;
+    }
+}
\ No newline at end of file
index 8654eea..ffa28ce 100644 (file)
@@ -2,6 +2,7 @@
 
 class Config {
   const PATH = '/etc/musiikki.conf';
+  const PATH_DLNA = '/etc/minidlna.conf';
   const SHARE_READ = 'musicread';
   const SHARE_WRITE = 'musicwrite';
 
@@ -20,6 +21,7 @@ class Config {
   private function __construct($path)
   {
     $this->loadValues($path);
+    $this->loadMiniDLNA(static::PATH_DLNA);
   }
 
   private function loadValues($path)
@@ -43,6 +45,29 @@ class Config {
     fclose($f);
   }
 
+  private function loadMiniDLNA($path)
+  {
+    if (!is_readable($path))
+      throw new Exception('Cannot open config file ' . $path);
+
+    $f = fopen($path, 'r');
+    if ($f === false)
+      throw new Exception('Cannot open config file ' . $path);
+
+    while (($line = fgets($f)) !== false) {
+      $line = trim($line);
+      if (substr($line,0,1) == '#') continue;
+      if (!strlen($line)) continue;
+      if (substr($line,0,10) != 'media_dir=') continue;
+
+      $parts = explode('=', $line, 2);
+      $details = explode(',', $parts[1], 2);
+      $this->values[$parts[0].'_'.$details[0]] = $details[1];
+    }
+
+    fclose($f);
+  }
+
   public function get($name)
   {
     if (!array_key_exists($name, $this->values))
diff --git a/html/index.php b/html/index.php
new file mode 100644 (file)
index 0000000..694096a
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+require_once(__DIR__.'/../class/autoloader.class.php');
+
+if ($_SERVER['REQUEST_METHOD'] == 'GET') {
+    $template = new Template('main');
+    echo $template->render([]);
+} elseif ($_SERVER['REQUEST_METHOD'] == 'POST') {
+    $method = $_POST['action'] . 'Action';
+
+    header('Content-type: application/json; charset=UTF-8');
+    $data = AJAX::$method($_POST);
+    $return = json_encode($data);
+
+    if ($return === false) {
+       error_log('Return ' . var_export($data,true));
+       $return = json_encode(array('status' => false, 'error' => 'Rückgabedaten können nicht kodiert werden.'));
+    }
+
+    echo $return;
+}
\ No newline at end of file
diff --git a/html/main.js b/html/main.js
new file mode 100644 (file)
index 0000000..fc57f28
--- /dev/null
@@ -0,0 +1,93 @@
+function toggle_section(event)
+{
+    $(this).parent().find('ul').toggle();
+}
+
+var waiting_stop = false;
+var waiting_forward = true;
+function results_waiting_stop()
+{
+    waiting_stop = true;
+    if (waiting_forward)
+       waiting_forward = false;
+}
+
+function results_waiting()
+{
+    var max = $(window).width() - 120;
+    var step = 15;
+    var hr = $('div#results hr');
+    var margin = hr.css('marginLeft').replace('px','');
+    if (margin.length)
+       margin = parseInt(margin, 10);
+    else
+       margin = 0;
+
+    if (margin == 0 && waiting_stop) {
+       waiting_stop = false;
+    } else {
+       if (margin > max)
+           waiting_forward = false;
+       else if (margin == 0)
+           waiting_forward = true;
+
+       if (waiting_forward)
+           margin += step;
+       else
+           margin -= step;
+
+       hr.css('marginLeft', margin+'px');
+       setTimeout(results_waiting,200);
+    }
+}
+setTimeout(results_waiting_stop,20000);
+
+function submit_search()
+{
+    if (!$('input#search_keyword').val().length)
+       return false;
+
+    $('div#results h1').text('Results.');
+    open_page('results');
+    $('div#results div.w3-section').hide();
+    results_waiting();
+
+    $.post('index.php',
+          'action=search&' + $('div.w3-container#search form').serialize(),
+          function(data){
+              if (data) {
+                  $('div#results h1').text(data.count+' matches.');
+                  var result = $('<ul class="section">');
+
+                  for (section in data.list) {
+                      var dom_li = $('<li class="section">');
+                      var dom_div = $('<div class="section">');
+                      dom_div.append($('<strong class="w3-round">').text(section).click(toggle_section));
+
+                      var dom_ul = $('<ul class="files">').hide();
+                      for (var i=0; i < data.list[section].length; i++) {
+                          var item = $('<li>');
+                          if (i % 2 == 1)
+                              item.addClass('bg');
+                          item.append($('<div class="it">').html(data.list[section][i].title));
+                          item.append($('<div class="ip">').html(data.list[section][i].path));
+                          item.append($('<div class="in">').html(data.list[section][i].name));
+
+                          dom_ul.append(item);
+                      }
+                      dom_div.append(dom_ul);
+
+                      dom_li.append(dom_div);
+                      result.append(dom_li);
+                  }
+
+                  $('div#results div.w3-section').empty().append(result);
+                  $('div#results div.w3-section').show();
+                  // $('div#results div.waiting').hide();
+                  results_waiting_stop();
+              }
+          });
+
+    return false;
+}
+
index 415dd9e..055a39b 100644 (file)
@@ -6,3 +6,11 @@ body {font-size:16px;}
 div#pageheader {
     padding-bottom: 5px;
 }
+
+ul.section, ul.files {list-style-type: none; margin: 0; padding: 0;}
+ul.section li {margin-bottom: 0.2rem;}
+div.section strong {width: 100%; display: block; background: #87CEFF; padding: 0.1rem; cursor:pointer;}
+ul.files li {margin-bottom: 0.3rem; line-height: 1.15rem;}
+ul.files li div.it {font-size: 14px;}
+ul.files li div.ip, ul.files li div.in {font-size: 12px;}
+li.bg {background: #f0f0f0;}
diff --git a/templates/main.phtml b/templates/main.phtml
new file mode 100644 (file)
index 0000000..cfec200
--- /dev/null
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<!-- Source: https://www.w3schools.com/w3css/tryw3css_templates_interior_design.htm -->
+<html class="ui-mobile">
+<head>
+<title><?=Config::main()->get('title')?></title>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<?=Utilities::formatCSS('w3.css')?>
+<?=Utilities::formatCSS('musiikki.css')?>
+<link rel="shortcut icon" href="<?php echo Config::main()->get('favicon')?>">
+<?=Utilities::formatScript('jquery-1.10.2.min.js')?>
+<?=Utilities::formatScript('musiikki.js')?>
+<?=Utilities::formatScript('main.js')?>
+</head>
+
+<body>
+
+<!-- Sidebar/menu -->
+<nav class="w3-sidebar w3-blue w3-collapse w3-top w3-large w3-padding" style="z-index: 3; width: 300px; font-weight: bold; display: none;" id="mySidebar"><br>
+  <a href="javascript:void(0)" onclick="w3_close()" class="w3-button w3-hide-large w3-display-topleft" style="width:100%;font-size:22px">Close Menu</a>
+  <div class="w3-container">
+    <h3 class="w3-padding-64"><b><?=Config::main()->get('title')?></b></h3>
+  </div>
+  <div class="w3-bar-block" style="padding-top:5px;">
+    <a href="/" onclick="open_page('home')" class="w3-bar-item w3-button w3-hover-white">Home</a>
+    <a href="#" onclick="open_page('search')" class="w3-bar-item w3-button w3-hover-white">Search</a> 
+  </div>
+</nav>
+
+<!-- Top menu on small screens -->
+<header class="w3-container w3-top w3-hide-large w3-blue w3-xlarge w3-padding">
+  <a href="javascript:void(0)" class="w3-button w3-blue w3-margin-right" onclick="w3_open()" title="Menu"><b>=</b></a>
+   <span><?=Config::main()->get('title')?></span>
+</header>
+
+<!-- Overlay effect when opening sidebar on small screens -->
+<div class="w3-overlay w3-hide-large" onclick="w3_close()" style="cursor: pointer; display: none;" title="close side menu" id="myOverlay"></div>
+
+<!-- !PAGE CONTENT! -->
+<div class="w3-main" style="margin-left:340px;margin-right:40px">
+
+<?php echo Template::html('main_home'); ?>
+<?php echo Template::html('search'); ?>
+<?php echo Template::html('results'); ?>
+
+<!-- End page content -->
+</div>
+
+</body>
+</html>
diff --git a/templates/main_home.phtml b/templates/main_home.phtml
new file mode 100644 (file)
index 0000000..52e0e20
--- /dev/null
@@ -0,0 +1,6 @@
+<!-- Home -->
+<div class="w3-container" id="home" style="margin-top:80px">
+  <h1 class="w3-xxxlarge"><b><?=Config::main()->get('title')?></b></h1>
+  <hr style="width:50px;border:5px solid blue" class="w3-round">
+  <p>Willkommen auf dem Infodrom MediaServer.</p>
+</div>
diff --git a/templates/results.phtml b/templates/results.phtml
new file mode 100644 (file)
index 0000000..7dd7204
--- /dev/null
@@ -0,0 +1,7 @@
+<!-- Search -->
+<div class="w3-container" id="results" style="margin-top:75px" style="display:none;">
+  <h1 class="w3-xxxlarge w3-text-blue"><b>Search.</b></h1>
+  <hr style="width:50px;border:5px solid blue" class="w3-round">
+  <div class="w3-section" style="display:none;">
+  </div>
+</div>
diff --git a/templates/search.phtml b/templates/search.phtml
new file mode 100644 (file)
index 0000000..a610d62
--- /dev/null
@@ -0,0 +1,12 @@
+<!-- Search -->
+<div class="w3-container" id="search" style="margin-top:75px" style="display:none;">
+  <h1 class="w3-xxxlarge w3-text-blue"><b>Search.</b></h1>
+  <hr style="width:50px;border:5px solid blue" class="w3-round">
+  <form>
+    <div class="w3-section">
+      <label>Suchwort</label>
+      <input class="w3-input w3-border" name="keyword" id="search_keyword" requiblue="" type="text">
+    </div>
+    <button type="submit" class="w3-button w3-block w3-padding-large w3-blue w3-margin-bottom" onclick="return submit_search()">Suchen</button>
+  </form>
+</div>