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();
+ }
+
}
--- /dev/null
+<?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
class Config {
const PATH = '/etc/musiikki.conf';
+ const PATH_DLNA = '/etc/minidlna.conf';
const SHARE_READ = 'musicread';
const SHARE_WRITE = 'musicwrite';
private function __construct($path)
{
$this->loadValues($path);
+ $this->loadMiniDLNA(static::PATH_DLNA);
}
private function loadValues($path)
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))
--- /dev/null
+<?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
--- /dev/null
+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;
+}
+
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;}
--- /dev/null
+<!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>
--- /dev/null
+<!-- 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>
--- /dev/null
+<!-- 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>
--- /dev/null
+<!-- 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>