diff --git a/app/src/components/FileBrowser.js b/app/src/components/FileBrowser.js
index e244c5f9..39f3f6b7 100644
--- a/app/src/components/FileBrowser.js
+++ b/app/src/components/FileBrowser.js
@@ -19,7 +19,6 @@ import {SortableTable} from "./SortableTable";
import {useBrowseFiles, useMediaDirectory, useWROLMode} from "../hooks/customHooks";
import {DirectoryRefreshButton, FileRowTagIcon, FilesRefreshButton} from "./Files";
import {FilePreviewContext} from "./FilePreview";
-import {StatusContext} from "../contexts/contexts";
function depthIndentation(path) {
// Repeated spaces for every folder a path is in.
diff --git a/modules/archive/lib.py b/modules/archive/lib.py
index cf92fd58..efa4ff4d 100644
--- a/modules/archive/lib.py
+++ b/modules/archive/lib.py
@@ -16,7 +16,8 @@ from sqlalchemy.orm import Session
from modules.archive.models import Domain, Archive
from wrolpi.cmd import READABILITY_BIN, SINGLE_FILE_BIN, CHROMIUM
-from wrolpi.common import get_media_directory, logger, extract_domain, chdir, escape_file_name, aiohttp_post
+from wrolpi.common import get_media_directory, logger, extract_domain, chdir, escape_file_name, aiohttp_post, \
+ format_html_string, split_lines_by_length
from wrolpi.dates import now, Seconds
from wrolpi.db import get_db_session, get_db_curs, optional_session
from wrolpi.errors import UnknownArchive, InvalidOrderBy
@@ -238,15 +239,18 @@ async def do_archive(url: str) -> Archive:
if readability:
# Write the readability parts to their own files. Write what is left after pops to the JSON file.
with archive_files.readability.open('wt') as fh:
- fh.write(readability.pop('content'))
+ content = format_html_string(readability.pop('content'))
+ fh.write(content)
with archive_files.readability_txt.open('wt') as fh:
readability_txt = readability.pop('textContent')
+ readability_txt = split_lines_by_length(readability_txt)
fh.write(readability_txt)
else:
# No readability was returned, so there are no files.
archive_files.readability_txt = archive_files.readability = None
# Store the single-file HTML in its own file.
+ singlefile = format_html_string(singlefile)
archive_files.singlefile.write_text(singlefile)
if screenshot:
@@ -258,7 +262,7 @@ async def do_archive(url: str) -> Archive:
readability = readability or {}
readability['url'] = url
with archive_files.readability_json.open('wt') as fh:
- fh.write(json.dumps(readability))
+ fh.write(json.dumps(readability, indent=2))
# Create any File models that we can, index them all.
paths = (
diff --git a/modules/archive/test/test_lib.py b/modules/archive/test/test_lib.py
index ecf8591c..67d57026 100644
--- a/modules/archive/test/test_lib.py
+++ b/modules/archive/test/test_lib.py
@@ -24,7 +24,7 @@ def make_fake_request_archive(readability=True, screenshot=True, title=True):
Image.new('RGB', (1, 1), color='grey').save(fh)
fh.seek(0)
image = fh.read()
- singlefile = '\ntest single-file\nジにてこちら\n
some title'
r = dict(
content=f'test readability content',
textContent='test readability textContent',
@@ -298,15 +298,35 @@ async def test_new_archive(test_session, fake_now):
assert archive1.url is not None
assert archive1.domain is not None
- # The actual files were dumped and read correctly.
- with open(archive1.singlefile_path) as fh:
- assert fh.read() == '
+
+
+ test single-file
+ジにてこちら
+
+
+ some title
+
+
+
+'''
+ assert archive1.readability_path.read_text() == '''
+
+
+ test readability content
+
+
+
+'''
with open(archive1.readability_txt_path) as fh:
assert fh.read() == 'test readability textContent'
- with open(archive1.readability_json_path) as fh:
- assert json.load(fh) == {'title': 'ジにてこちら', 'url': 'https://example.com'}
+ assert archive1.readability_json_path.read_text() == '''{
+ "title": "\\u30b8\\u306b\\u3066\\u3053\\u3061\\u3089",
+ "url": "https://example.com"
+}'''
fake_now(datetime(2000, 1, 2))
archive2 = await do_archive('https://example.com')
@@ -613,7 +633,9 @@ async def test_archive_download_index(test_session, test_directory, image_file):
assert isinstance(archive, lib.Archive), 'Did not get an archive'
assert archive.singlefile_path and archive.singlefile_path.exists() and \
- archive.singlefile_path.read_text() == singlefile, 'Singlefile was not stored'
+ archive.singlefile_path.read_text() == \
+ '\n \n \n the singlefile\n \n \n\n', \
+ 'Singlefile was not formatted'
assert archive.readability_path and archive.readability_path.exists()
assert archive.readability_json_path
assert archive.readability_txt_path and archive.readability_txt_path.exists()
diff --git a/modules/videos/downloader.py b/modules/videos/downloader.py
index b42e11de..4b130141 100755
--- a/modules/videos/downloader.py
+++ b/modules/videos/downloader.py
@@ -13,7 +13,8 @@ from yt_dlp import YoutubeDL
from yt_dlp.extractor import YoutubeTabIE # noqa
from wrolpi.cmd import YT_DLP_BIN
-from wrolpi.common import logger, get_media_directory, escape_file_name, resolve_generators, background_task
+from wrolpi.common import logger, get_media_directory, escape_file_name, resolve_generators, background_task, \
+ format_json_file
from wrolpi.dates import now
from wrolpi.db import get_db_session
from wrolpi.db import optional_session
@@ -331,6 +332,9 @@ class VideoDownloader(Downloader, ABC):
video.channel_id = channel_id
video_id = video.id
+ if video.info_json_path:
+ format_json_file(video.info_json_path)
+
session.commit()
if download.settings and (tag_names := download.settings.get('tag_names')):
diff --git a/modules/videos/models.py b/modules/videos/models.py
index d0d316dd..a9844237 100644
--- a/modules/videos/models.py
+++ b/modules/videos/models.py
@@ -276,7 +276,8 @@ class Video(ModelHelper, Base):
@property
def caption_files(self) -> List[dict]:
- return self.file_group.my_files('text/vtt') + self.file_group.my_files('text/srt')
+ return self.file_group.my_files('text/vtt') + self.file_group.my_files('text/srt') \
+ + self.file_group.my_files('application/x-subrip')
@property
def caption_paths(self) -> List[pathlib.Path]:
diff --git a/wrolpi/common.py b/wrolpi/common.py
index 4eb8bffd..0c5ffe8e 100644
--- a/wrolpi/common.py
+++ b/wrolpi/common.py
@@ -1477,3 +1477,45 @@ def extract_headlines(entries: List[str], search_str: str) -> List[Tuple[str, fl
headlines = [tuple(i) for i in curs.fetchall()]
return headlines
+
+
+def format_json_file(file: pathlib.Path, indent: int = 2):
+ """Reformat the contents of a JSON file to include indentation to increase readability."""
+ if not indent or indent <= 0:
+ raise RuntimeError('Ident must be greater than 0')
+ if not file or not file.is_file():
+ raise RuntimeError(f'File does not exist: {file}')
+
+ with file.open('rt') as fh:
+ content = json.load(fh)
+
+ copy = file.with_suffix('.json2')
+ try:
+ with copy.open('wt') as fh:
+ json.dump(content, fh, indent=indent)
+ copy.rename(file)
+ finally:
+ if copy.is_file():
+ copy.unlink()
+
+
+def format_html_string(html: str) -> str:
+ soup = BeautifulSoup(html)
+ return soup.prettify()
+
+
+def format_html_file(file: pathlib.Path):
+ """Reformat the contents of an HTML file to include indentation to increase readability."""
+ if not file or not file.is_file():
+ raise RuntimeError(f'File does not exist: {file}')
+
+ pretty = format_html_string(file.read_text())
+
+ copy = file.with_suffix('.html2')
+ try:
+ with copy.open('wt') as fh:
+ fh.write(pretty)
+ copy.rename(file)
+ finally:
+ if copy.is_file():
+ copy.unlink()
diff --git a/wrolpi/files/test/test_lib.py b/wrolpi/files/test/test_lib.py
index 75b42378..1b6bcdfb 100644
--- a/wrolpi/files/test/test_lib.py
+++ b/wrolpi/files/test/test_lib.py
@@ -183,7 +183,7 @@ async def test__upsert_files(test_session, make_files_structure, test_directory,
assert_file_groups([
{'primary_path': video_file, 'idempotency': idempotency, 'modification_datetime': foo_mtime, 'indexed': False,
'files': [
- {'path': srt_file3, 'size': 951, 'suffix': '.en.srt', 'mimetype': 'text/srt'},
+ {'path': srt_file3, 'size': 951, 'suffix': '.en.srt', 'mimetype': 'application/x-subrip'},
{'path': video_file, 'size': 1056318, 'suffix': '.mp4', 'mimetype': 'video/mp4'},
]},
{'primary_path': bar, 'idempotency': idempotency, 'indexed': False,
@@ -210,7 +210,7 @@ async def test__upsert_files(test_session, make_files_structure, test_directory,
assert_file_groups([
{'primary_path': video_file, 'idempotency': idempotency, 'modification_datetime': foo_mtime, 'indexed': True,
'files': [
- {'path': srt_file3, 'size': 951, 'suffix': '.en.srt', 'mimetype': 'text/srt'},
+ {'path': srt_file3, 'size': 951, 'suffix': '.en.srt', 'mimetype': 'application/x-subrip'},
{'path': video_file, 'size': 1056318, 'suffix': '.mp4', 'mimetype': 'video/mp4'},
]},
{'primary_path': bar, 'idempotency': idempotency, 'indexed': False,
diff --git a/wrolpi/test/test_common.py b/wrolpi/test/test_common.py
index 0c4d773b..3048718f 100644
--- a/wrolpi/test/test_common.py
+++ b/wrolpi/test/test_common.py
@@ -1,5 +1,6 @@
import asyncio
import ctypes.wintypes
+import json
import multiprocessing
import os
import pathlib
@@ -719,3 +720,65 @@ Paragraph outside an element.'''
)
def test_human_bandwidth(bps, expected):
assert common.human_bandwidth(bps) == expected
+
+
+def test_format_json_file():
+ with tempfile.TemporaryDirectory() as d:
+ with tempfile.NamedTemporaryFile(suffix='.json', dir=d) as fh:
+ file = pathlib.Path(fh.name)
+ file.write_text(json.dumps({
+ 'one': 1,
+ 'two': 2,
+ 'three': 3,
+ 'four': 4,
+ 'five': 5,
+ 'six': 6,
+ 'seven': 7,
+ 'eight': 8,
+ 'nine': 9,
+ 'ten': 10,
+ }))
+ # Only one file was created.
+ assert len(list(file.parent.iterdir())) == 1
+
+ unformatted = '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10}'
+ assert file.read_text() == unformatted
+
+ common.format_json_file(file)
+ assert file.read_text() == '''{
+ "one": 1,
+ "two": 2,
+ "three": 3,
+ "four": 4,
+ "five": 5,
+ "six": 6,
+ "seven": 7,
+ "eight": 8,
+ "nine": 9,
+ "ten": 10
+}'''
+ # The copy was deleted.
+ assert len(list(file.parent.iterdir())) == 1
+
+
+def test_format_html_file():
+ with tempfile.NamedTemporaryFile() as fh:
+ file = pathlib.Path(fh.name)
+ unformatted = 'TitleBody'
+ file.write_text(unformatted)
+
+ assert file.read_text() == unformatted
+
+ common.format_html_file(file)
+ assert file.read_text() == '''
+
+
+
+ Title
+
+
+
+ Body
+
+
+'''