mirror of
https://github.com/webrecorder/pywb.git
synced 2025-03-22 14:24:27 +01:00
add overridable error and query views, with extensible get_query_params() and process_cdx_query() to extend cdx for query view add get_top_url() for adding custom top_url for frame insert add call_with_params() for adding custom params to environ
178 lines
5.7 KiB
Python
178 lines
5.7 KiB
Python
from pywb.utils.timeutils import timestamp_to_datetime, timestamp_to_sec
|
|
from pywb.utils.timeutils import timestamp_now
|
|
from six.moves.urllib.parse import urlsplit
|
|
|
|
from jinja2 import Environment
|
|
from jinja2 import FileSystemLoader, PackageLoader, ChoiceLoader
|
|
|
|
import json
|
|
import os
|
|
|
|
|
|
# ============================================================================
|
|
class FileOnlyPackageLoader(PackageLoader):
|
|
def get_source(self, env, template):
|
|
dir_, file_ = os.path.split(template)
|
|
return super(FileOnlyPackageLoader, self).get_source(env, file_)
|
|
|
|
|
|
# ============================================================================
|
|
class RelEnvironment(Environment):
|
|
"""Override join_path() to enable relative template paths."""
|
|
def join_path(self, template, parent):
|
|
return os.path.join(os.path.dirname(parent), template)
|
|
|
|
|
|
# ============================================================================
|
|
class JinjaEnv(object):
|
|
def __init__(self, paths=['templates', '.', '/'],
|
|
packages=['pywb'],
|
|
globals=None,
|
|
overlay=None):
|
|
|
|
self._init_filters()
|
|
|
|
loader = ChoiceLoader(self._make_loaders(paths, packages))
|
|
|
|
if overlay:
|
|
jinja_env = overlay.jinja_env.overlay(loader=loader, trim_blocks=True)
|
|
else:
|
|
jinja_env = RelEnvironment(loader=loader, trim_blocks=True)
|
|
|
|
jinja_env.filters.update(self.filters)
|
|
if globals:
|
|
jinja_env.globals.update(globals)
|
|
self.jinja_env = jinja_env
|
|
|
|
def _make_loaders(self, paths, packages):
|
|
loaders = []
|
|
# add loaders for paths
|
|
for path in paths:
|
|
loaders.append(FileSystemLoader(path))
|
|
|
|
# add loaders for all specified packages
|
|
for package in packages:
|
|
loaders.append(FileOnlyPackageLoader(package))
|
|
|
|
return loaders
|
|
|
|
def template_filter(self, param=None):
|
|
def deco(func):
|
|
name = param or func.__name__
|
|
self.filters[name] = func
|
|
return func
|
|
|
|
return deco
|
|
|
|
def _init_filters(self):
|
|
self.filters = {}
|
|
|
|
@self.template_filter()
|
|
def format_ts(value, format_='%a, %b %d %Y %H:%M:%S'):
|
|
if format_ == '%s':
|
|
return timestamp_to_sec(value)
|
|
else:
|
|
value = timestamp_to_datetime(value)
|
|
return value.strftime(format_)
|
|
|
|
@self.template_filter('urlsplit')
|
|
def get_urlsplit(url):
|
|
split = urlsplit(url)
|
|
return split
|
|
|
|
@self.template_filter()
|
|
def tojson(obj):
|
|
return json.dumps(obj)
|
|
|
|
|
|
# ============================================================================
|
|
class BaseInsertView(object):
|
|
def __init__(self, jenv, insert_file, banner_file=''):
|
|
self.jenv = jenv
|
|
self.insert_file = insert_file
|
|
self.banner_file = banner_file
|
|
|
|
def render_to_string(self, env, **kwargs):
|
|
template = self.jenv.jinja_env.get_template(self.insert_file)
|
|
params = env.get('webrec.template_params')
|
|
if params:
|
|
kwargs.update(params)
|
|
|
|
return template.render(**kwargs)
|
|
|
|
|
|
# ============================================================================
|
|
class HeadInsertView(BaseInsertView):
|
|
def create_insert_func(self, wb_url,
|
|
wb_prefix,
|
|
host_prefix,
|
|
top_url,
|
|
env,
|
|
is_framed,
|
|
coll='',
|
|
include_ts=True):
|
|
|
|
url = wb_url.get_url()
|
|
|
|
include_wombat = not wb_url.is_banner_only
|
|
|
|
wbrequest = {'host_prefix': host_prefix,
|
|
'wb_prefix': wb_prefix,
|
|
'wb_url': wb_url,
|
|
'coll': coll,
|
|
'env': env,
|
|
'options': {'is_framed': is_framed},
|
|
'rewrite_opts': {}
|
|
}
|
|
|
|
def make_head_insert(rule, cdx):
|
|
return (self.render_to_string(env, wbrequest=wbrequest,
|
|
cdx=cdx,
|
|
top_url=top_url,
|
|
include_ts=include_ts,
|
|
include_wombat=include_wombat,
|
|
banner_html=self.banner_file,
|
|
rule=rule))
|
|
return make_head_insert
|
|
|
|
|
|
# ============================================================================
|
|
class TopFrameView(BaseInsertView):
|
|
def get_top_frame(self, wb_url,
|
|
wb_prefix,
|
|
host_prefix,
|
|
env,
|
|
frame_mod,
|
|
replay_mod,
|
|
coll='',
|
|
extra_params=None):
|
|
|
|
embed_url = wb_url.to_str(mod=replay_mod)
|
|
|
|
if wb_url.timestamp:
|
|
timestamp = wb_url.timestamp
|
|
else:
|
|
timestamp = timestamp_now()
|
|
|
|
wbrequest = {'host_prefix': host_prefix,
|
|
'wb_prefix': wb_prefix,
|
|
'wb_url': wb_url,
|
|
'coll': coll,
|
|
|
|
'options': {'frame_mod': frame_mod,
|
|
'replay_mod': replay_mod},
|
|
}
|
|
|
|
params = dict(embed_url=embed_url,
|
|
wbrequest=wbrequest,
|
|
timestamp=timestamp,
|
|
url=wb_url.get_url(),
|
|
banner_html=self.banner_file)
|
|
|
|
if extra_params:
|
|
params.update(extra_params)
|
|
|
|
return self.render_to_string(env, **params)
|
|
|
|
|