Commit 33d28381 authored by Jean-Francois Dockes's avatar Jean-Francois Dockes
Browse files

httpd ckpt

parent ca9fb0fb
#!/usr/bin/env python
#
# Copyright (C) 2016 J.F.Dockes
# Copyright (C) 2017 J.F.Dockes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
......@@ -15,7 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import sys
import os
import json
......@@ -24,11 +23,13 @@ import re
import conftree
import cmdtalkplugin
import urllib
import threading
import uprclfolders
import uprcltags
import uprcluntagged
import uprclsearch
import uprclhttp
from uprclutils import *
from recoll import recoll
......@@ -46,7 +47,7 @@ dispatcher = cmdtalkplugin.Dispatch()
msgproc = cmdtalkplugin.Processor(dispatcher)
def uprcl_init():
global httphp, pathprefix, uprclhost, pathmap, rclconfdir, g_rcldocs
global httphp, pathprefix, uprclhostport, pathmap, rclconfdir, g_rcldocs
if "UPMPD_HTTPHOSTPORT" not in os.environ:
raise Exception("No UPMPD_HTTPHOSTPORT in environment")
......@@ -58,8 +59,8 @@ def uprcl_init():
raise Exception("No UPMPD_CONFIG in environment")
upconfig = conftree.ConfSimple(os.environ["UPMPD_CONFIG"])
uprclhost = upconfig.get("uprclhost")
if uprclhost is None:
uprclhostport = upconfig.get("uprclhostport")
if uprclhostport is None:
raise Exception("uprclhost not in config")
pthstr = upconfig.get("uprclpaths")
......@@ -80,13 +81,20 @@ def uprcl_init():
uprcltags.recolltosql(g_rcldocs)
uprcluntagged.recoll2untagged(g_rcldocs)
host,port = uprclhostport.split(':')
httpthread = threading.Thread(target=uprclhttp.runHttp,
kwargs = {'host':host , 'port':int(port),
'pathmap':pathmap})
httpthread.daemon = True
httpthread.start()
@dispatcher.record('trackuri')
def trackuri(a):
msgproc.log("trackuri: [%s]" % a)
if 'path' not in a:
raise Exception("trackuri: no 'path' in args")
path = urllib.quote(a['path'])
media_url = rclpathtoreal(path, pathprefix, uprclhost, pathmap)
media_url = rclpathtoreal(path, pathprefix, uprclhostport, pathmap)
msgproc.log("trackuri: returning: %s" % media_url)
return {'media_url' : media_url}
......
#
# Copyright (C) 2017 J.F.Dockes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import shlex
......
#!/usr/bin/env python
#
# Copyright (C) 2017 J.F.Dockes
#
# HTTP Range code:
# Portions Copyright (C) 2009,2010 Xyne
# Portions Copyright (C) 2011 Sean Goller
# https://github.com/smgoller/rangehttpserver/blob/master/RangeHTTPServer.py
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import SocketServer
import BaseHTTPServer
import SimpleHTTPServer
import os
import posixpath
import BaseHTTPServer
import urllib
import cgi
import shutil
import mimetypes
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from uprclutils import uplog
__version__ = "0.1"
class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""Simple HTTP request handler with GET and HEAD commands.
This serves files from the current directory and any of its
subdirectories. The MIME type for files is determined by
calling the .guess_type() method.
The GET and HEAD requests are identical except that the HEAD
request omits the actual contents of the file.
"""
server_version = "RangeHTTP/" + __version__
def do_GET(self):
"""Serve a GET request."""
f, start_range, end_range = self.send_head()
if f:
uplog("do_GET: Got (%d,%d)" % (start_range,end_range))
f.seek(start_range, 0)
chunk = 0x1000
total = 0
while chunk > 0:
if start_range + chunk > end_range:
chunk = end_range - start_range
try:
self.wfile.write(f.read(chunk))
except:
break
total += chunk
start_range += chunk
f.close()
def do_HEAD(self):
"""Serve a HEAD request."""
f, start_range, end_range = self.send_head()
if f:
f.close()
def send_head(self):
"""Common code for GET and HEAD commands.
This sends the response code and MIME headers.
Return value is either a file object (which has to be copied
to the outputfile by the caller unless the command was HEAD,
and must be closed by the caller under all circumstances), or
None, in which case the caller has nothing further to do.
"""
uplog("HTTP: path: %s" % self.path)
path = self.translate_path(self.path)
if not path or not os.path.exists(path):
self.send_error(404)
return (None, 0, 0)
if not os.path.isfile(path):
self.send_error(405)
return (None, 0, 0)
f = None
ctype = self.guess_type(path)
try:
f = open(path, 'rb')
except:
self.send_error(404, "File not found")
return (None, 0, 0)
if "Range" in self.headers:
self.send_response(206)
else:
self.send_response(200)
self.send_header("Content-type", ctype)
fs = os.fstat(f.fileno())
size = int(fs[6])
start_range = 0
end_range = size
self.send_header("Accept-Ranges", "bytes")
if "Range" in self.headers:
s, e = self.headers['range'][6:].split('-', 1)
sl = len(s)
el = len(e)
if sl > 0:
start_range = int(s)
if el > 0:
end_range = int(e) + 1
elif el > 0:
ei = int(e)
if ei < size:
start_range = size - ei
self.send_header("Content-Range",
'bytes ' + str(start_range) + '-' +
str(end_range - 1) + '/' + str(size))
self.send_header("Content-Length", end_range - start_range)
self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
self.end_headers()
#uplog("Sending Bytes %d to %d" % (start_range, end_range))
return (f, start_range, end_range)
def translate_path(self, opath):
path = urllib.unquote(opath)
for p in self.uprclpathmap.itervalues():
if path.startswith(p):
return path
uplog("HTTP: translate_path: %s not found in path map" % opath)
return None
def guess_type(self, path):
"""Guess the type of a file.
Argument is a PATH (a filename).
Return value is a string of the form type/subtype,
usable for a MIME Content-type header.
The default implementation looks the file's extension
up in the table self.extensions_map, using application/octet-stream
as a default; however it would be permissible (if
slow) to look inside the data to make a better guess.
"""
base, ext = posixpath.splitext(path)
if ext in self.extensions_map:
return self.extensions_map[ext]
ext = ext.lower()
if ext in self.extensions_map:
return self.extensions_map[ext]
else:
return self.extensions_map['']
if not mimetypes.inited:
mimetypes.init() # try to read system mime.types
extensions_map = mimetypes.types_map.copy()
extensions_map.update({
'': 'application/octet-stream', # Default
'.mp4': 'video/mp4',
'.ogg': 'video/ogg',
})
class ThreadingSimpleServer(SocketServer.ThreadingMixIn,
BaseHTTPServer.HTTPServer):
pass
def runHttp(host='', port=8080, pathmap={}):
# Set pathmap as request handler class variable
RangeHTTPRequestHandler.uprclpathmap = pathmap
server = ThreadingSimpleServer((host, port), RangeHTTPRequestHandler)
while 1:
server.handle_request()
#!/usr/bin/env python
#
# Copyright (C) 2017 J.F.Dockes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import re
......
from __future__ import print_function
#
# Copyright (C) 2017 J.F.Dockes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import sqlite3
......@@ -189,8 +203,7 @@ def rootentries(pid):
# Check what tags still have multiple values inside the selected set,
# and return their list.
def subtreetags(sqconn, recs):
docids = ','.join([str(r[0]) for r in recs])
def subtreetags(sqconn, docids):
uplog("subtreetags, docids %s" % docids)
c1 = sqconn.cursor()
tags = []
......@@ -206,7 +219,15 @@ def subtreetags(sqconn, recs):
tags.append(tt)
return tags
def subtreealbums(sqconn, recs):
def subtreealbums(sqconn, docids):
c1 = sqconn.cursor()
albids = []
stmt = 'SELECT album_id from tracks where docidx IN (' + docids + ') ' + \
'GROUP BY album_id'
c1.execute(stmt)
for r in c1:
albids.append(r[0])
return albids
# Main browsing routine. Given an objid, translate it into a select
# statement, plus further processing, and return the corresponding
......@@ -222,6 +243,11 @@ def seltagsbrowse(pid, qpath, flag, httphp, pathprefix):
elt = qpath[i]
if elt.startswith('='):
col = tagtables[elt[1:]]
#detect the special values albums items etc. here. Their
#presence changes how we process the rest (showing tracks and
#albums and not dealing with other tags any more
selwhere = selwhere + ' AND ' if selwhere else ' WHERE '
if i == qlen - 1:
# We want to display all unique values for the column
......@@ -249,7 +275,18 @@ def seltagsbrowse(pid, qpath, flag, httphp, pathprefix):
uplog("seltagsbrowse: executing <%s> values %s" % (stmt, values))
c.execute(stmt, values)
recs = c.fetchall()
subqs = subtreetags(sqconn, recs)
docids = ','.join([str(r[0]) for r in recs])
albids = subtreealbums(sqconn, docids)
if len(albids) > 1:
id = pid + '$albums'
entries.append(rcldirentry(id, pid, str(len(albids)) + ' albums'))
id = pid + '$items'
entries.append(rcldirentry(id, pid, str(len(recs)) + ' items'))
elif len(albids) == 1:
id = pid + '$items'
entries.append(rcldirentry(id, pid, str(len(recs)) + ' items'))
subqs = subtreetags(sqconn, docids)
if not subqs:
for r in recs:
docidx = r[0]
......
#
# Copyright (C) 2017 J.F.Dockes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import shlex
......
#
# Copyright (C) 2017 J.F.Dockes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import sys
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment