Skip to content

Commit c2ba9a2

Browse files
authored
Merge pull request #35 from pganssle/adjust_resources
By default pull default resources from the package data
2 parents 9b8d586 + 55af972 commit c2ba9a2

File tree

12 files changed

+302
-124
lines changed

12 files changed

+302
-124
lines changed

src/audio_feeder/app.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
from . import cache_utils
99
from . import database_handler as dh
10+
from . import resources
11+
from .config import read_from_config
1012
from .pages import root
1113

1214

@@ -57,6 +59,12 @@ def create_app(load_db=True, populate_qr_cache=True, progressbar=False, block=Fa
5759
for warning in warnings:
5860
log.warning(*warning)
5961

62+
log.info("Refreshing fonts on disk")
63+
static_media_path = read_from_config("static_media_path")
64+
resources.update_resource(
65+
"audio_feeder.data.site.fonts", static_media_path / "fonts"
66+
)
67+
6068
log.info("Creating Flask application")
6169
app = Flask(__name__)
6270
app.register_blueprint(root)

src/audio_feeder/cli.py

Lines changed: 5 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -137,34 +137,10 @@ def install(config_dir, config_name):
137137
Installs the feeder configuration and populates the initial file structures
138138
with the default package data.
139139
"""
140-
import importlib
141140
import os
142141
import warnings
143-
from importlib import resources
144142

145-
from . import config
146-
147-
def _copy_resource(
148-
resource: importlib.abc.Traversable, target_dir: pathlib.Path
149-
) -> None:
150-
if resource.is_file():
151-
if not target_dir.exists():
152-
target_dir.mkdir(parents=True)
153-
154-
target_loc = target_dir / resource.name
155-
target_loc.write_bytes(resource.read_bytes())
156-
else:
157-
for child in resource.iterdir():
158-
if (
159-
child.name.endswith(".py")
160-
or child.name.endswith(".pyc")
161-
or child.name == "__pycache__"
162-
):
163-
continue
164-
if child.is_dir():
165-
_copy_resource(child, target_dir / child.name)
166-
else:
167-
_copy_resource(child, target_dir)
143+
from . import config, resources
168144

169145
# Assign a configuration directory
170146
if config_dir is None:
@@ -195,21 +171,13 @@ def _copy_resource(
195171
config_obj.to_file(config_loc)
196172

197173
# Create the directories that need to exist, if they don't already
198-
make_dir_entries = (
199-
"templates_base_loc",
200-
"entry_templates_loc",
201-
"pages_templates_loc",
202-
"rss_templates_loc",
203-
"rss_entry_templates_loc",
204-
"static_media_path",
205-
) # Absolute paths
174+
make_dir_entries = ("static_media_path",) # Absolute paths
206175

207176
make_dir_directories = [config_obj[x] for x in make_dir_entries]
208177
static_paths = [
209178
os.path.join(config_obj.static_media_path, config_obj[x])
210179
for x in (
211180
"site_images_loc",
212-
"css_loc",
213181
"cover_cache_path",
214182
"qr_cache_path",
215183
"media_cache_path",
@@ -242,23 +210,9 @@ def _copy_resource(
242210
raise
243211

244212
# Copy all package data as appropriate
245-
site = resources.files("audio_feeder.data.site")
246-
templates = resources.files("audio_feeder.data.templates")
247-
248-
_copy_resource(site, pathlib.Path(config_obj["static_media_path"]))
249-
250-
# Directories
251-
pkg_dir_map = {
252-
"entry_templates_loc": "entry_types",
253-
"pages_templates_loc": "pages",
254-
"rss_templates_loc": "rss",
255-
"rss_entry_templates_loc": "entry_types",
256-
}
257-
258-
pkg_dir_map = {config_obj[k]: v for k, v in pkg_dir_map.items()}
259-
260-
for target_loc, resource_loc in pkg_dir_map.items():
261-
_copy_resource(templates / resource_loc, pathlib.Path(target_loc))
213+
resources.update_resource(
214+
"audio_feeder.data.site", pathlib.Path(config_obj["static_media_path"])
215+
)
262216

263217

264218
@cli.group()

src/audio_feeder/config.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ class Configuration:
120120

121121
static_media_url: str = TemplateStr("{{URL}}/static")
122122

123+
# If true, this will not inject the default CSS files.
124+
disable_default_css: bool = False
125+
123126
# Relative to static
124127
media_path: str = "media"
125128
site_images_loc: str = "images/site-images"
@@ -132,7 +135,8 @@ class Configuration:
132135
rss_feed_urls: str = "rss/{id}.xml"
133136

134137
# Relative to others
135-
main_css_files: typing.Sequence[str] = ("main.css", "fontawesome-subset.css") # CSS
138+
main_css_files: typing.Sequence[str] = () # Deprecated, no longer used
139+
extra_css_files: typing.Sequence[str] = ()
136140
thumb_max: typing.Tuple[int, int] = (200, 400) # width, height
137141
base_protocol: str = "http"
138142
base_host: str = "localhost"

src/audio_feeder/data/site/css/main.css renamed to src/audio_feeder/data/css/main.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ div.topnav-icons {
276276

277277
.modal-window {
278278
display: inline-block;
279-
position: absolute;
279+
position: fixed;
280280
top: 50%;
281281
left: 50%;
282282
transform: translate(-50%, -50%);

src/audio_feeder/page_generator.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from jinja2 import Template
1010

11+
from . import resources
1112
from .config import read_from_config
1213
from .html_utils import TagStripper
1314
from .media_renderer import RenderModes
@@ -132,27 +133,36 @@ def truncation_point(self, description):
132133

133134
return orig_pos
134135

136+
def _get_template(self, loc, name, resource_default):
137+
template_loc = os.path.join(loc, name)
138+
139+
if not os.path.exists(template_loc):
140+
# Load from resource
141+
return Template(resources.get_text_resource(resource_default, name))
142+
else:
143+
with open(template_loc, "rt") as f:
144+
return Template(f.read())
145+
135146
def load_type(self, type_name):
136147
type_cache = getattr(self, "_load_type_cache", {})
137148
if type_name not in type_cache:
138-
et_loc = self.entry_templates_loc
139-
if not os.path.exists(et_loc):
140-
raise IOError("Entry templates directory does not exist.")
141-
142-
type_dir = os.path.join(et_loc, type_name)
143-
if not os.path.exists(type_dir):
144-
raise IOError(f"Type directory templates do not exist: {type_dir}")
145-
149+
type_dir = self.entry_templates_loc / type_name
146150
type_dict = {}
147-
for fname in os.listdir(type_dir):
148-
fpath = os.path.join(type_dir, fname)
149-
if not (os.path.isfile(fpath) and fpath.endswith(".tpl")):
150-
continue
151-
152-
tname = os.path.splitext(fname)[0]
153-
154-
with open(fpath, "r") as f:
155-
type_dict[tname] = Template(f.read())
151+
if type_dir.exists():
152+
for fpath in type_dir.glob("*.tpl"):
153+
type_dict[fpath.stem] = Template(fpath.read_text())
154+
else:
155+
resource = f"audio_feeder.data.templates.entry_types.{type_name}"
156+
for child in resources.get_children(resource):
157+
if child.is_dir() or not child.name.endswith(".tpl"):
158+
continue
159+
fname = os.path.splitext(child.name)[0]
160+
type_dict[fname] = Template(child.read_text())
161+
162+
if not type_dict:
163+
raise FileNotFounderror(
164+
f"No entry templates found for type {type_name}"
165+
)
156166

157167
type_cache[type_name] = type_dict
158168

src/audio_feeder/pages.py

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from audio_feeder import media_renderer as mr
1919
from audio_feeder import object_handler as oh
2020
from audio_feeder import page_generator as pg
21+
from audio_feeder import resources
2122
from audio_feeder import rss_feeds as rf
2223
from audio_feeder.config import read_from_config
2324
from audio_feeder.file_location import FileLocation
@@ -511,32 +512,37 @@ def get_sortable_args(args):
511512
return args
512513

513514

514-
def get_list_template():
515-
template = getattr(get_list_template, "_template", None)
516-
if template is None:
517-
template = _get_template("pages_templates_loc", "list.tpl")
518-
get_list_template._template = template
515+
@functools.cache
516+
def get_list_template() -> Template:
517+
template = _get_template(
518+
"pages_templates_loc",
519+
"list.tpl",
520+
resource_default="audio_feeder.data.templates.pages",
521+
)
519522

520523
return template
521524

522525

523-
def get_feed_template():
524-
template = getattr(get_feed_template, "_template", None)
525-
if template is None:
526-
template = _get_template("rss_templates_loc", "rss_feed.tpl")
527-
get_feed_template._template = template
528-
529-
return get_feed_template._template
530-
526+
@functools.cache
527+
def get_feed_template() -> Template:
528+
return _get_template(
529+
"rss_templates_loc",
530+
"rss_feed.tpl",
531+
resource_default="audio_feeder.data.templates.rss",
532+
)
531533

532-
def _get_template(loc_entry, template_name):
533-
template_loc = read_from_config(loc_entry)
534-
template_loc = os.path.join(template_loc, template_name)
535534

536-
with open(template_loc, "r") as f:
537-
template = Template(f.read())
535+
def _get_template(
536+
loc_entry: str, template_name: str, resource_default: typing.Optional[str] = None
537+
) -> Template:
538+
template_loc = read_from_config(loc_entry) / template_name
538539

539-
return template
540+
if template_loc.exists():
541+
return Template(template_loc.read_text())
542+
elif resource_default is not None:
543+
return Template(resources.get_text_resource(resource_default, template_name))
544+
else:
545+
raise FileNotFoundError(f"Could not find template: {template_loc}")
540546

541547

542548
def get_renderer(rss_renderer=False):
@@ -555,13 +561,28 @@ def get_renderer(rss_renderer=False):
555561
return renderer[rss_renderer]
556562

557563

558-
def get_css_links():
564+
@functools.cache
565+
def get_css_links() -> typing.Sequence[str]:
559566
resolver = get_resolver()
560567
css_loc = read_from_config("css_loc")
561-
css_locs = [
562-
os.path.join(css_loc, css_file)
563-
for css_file in read_from_config("main_css_files")
564-
]
568+
css_locs: typing.MutableSequence[str] = []
569+
if not read_from_config("disable_default_css"):
570+
static_path = read_from_config("static_media_path")
571+
default_loc = resolver.resolve_static(css_loc)
572+
default_path = default_loc.path
573+
assert default_path is not None
574+
resources.update_resource("audio_feeder.data.css", default_path)
575+
css_locs.extend(
576+
os.fspath(fpath.relative_to(static_path))
577+
for fpath in default_path.rglob("*.css")
578+
)
579+
580+
css_locs.extend(
581+
(
582+
os.path.join(css_loc, css_file)
583+
for css_file in read_from_config("extra_css_files")
584+
)
585+
)
565586

566587
css_paths = [resolver.resolve_static(css_relpath).url for css_relpath in css_locs]
567588

0 commit comments

Comments
 (0)