mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 10:51:36 -04:00
* Working through archive search. * Using custom hook. * Setting archive.contents duration creation. * Archive search and domain list use custom hooks. * Watching search param using value, not history. * Search params are preserved on load. Search and domain can be cleared. * Fixing archive external link. * Archive search form is new generic SearchInput. * Reworking Archives empty states. * Simplifying Archives logic. * Fixing bug which displayed the wrong empty state during loading. * Archives can be synced and deleted. * Changing wording of archive delete. * Removing URL table. * Deleting domain if it has no archives. * Fixing FE use of archive.url. Fixing bug with get_domains. * Universal results are displayed on Welcome page. * Creating ExternalLink to open a link in a new tab.g * Increasing size of search headers. * Adding divider to ease reading. * Adding More button below search results. * Disabling More buttons when there are no results. * Ordering videos by rank so linked results are at the top. Signed-off-by: Roland <roland@learningselfreliance.com>
109 lines
3.7 KiB
Python
109 lines
3.7 KiB
Python
from typing import Generator
|
|
|
|
from sqlalchemy import Column, Integer, String, ForeignKey, Computed
|
|
from sqlalchemy.orm import relationship, Session
|
|
from sqlalchemy.orm.collections import InstrumentedList
|
|
|
|
from wrolpi.common import ModelHelper, Base, tsvector
|
|
from wrolpi.dates import TZDateTime
|
|
from wrolpi.media_path import MediaPathType
|
|
|
|
|
|
class Archive(Base, ModelHelper):
|
|
__tablename__ = 'archive'
|
|
id = Column(Integer, primary_key=True)
|
|
|
|
domain_id = Column(Integer, ForeignKey('domains.id'))
|
|
domain = relationship('Domain', primaryjoin='Archive.domain_id==Domain.id')
|
|
|
|
singlefile_path = Column(MediaPathType)
|
|
readability_path = Column(MediaPathType)
|
|
readability_json_path = Column(MediaPathType)
|
|
readability_txt_path = Column(MediaPathType)
|
|
screenshot_path = Column(MediaPathType)
|
|
|
|
url = Column(String)
|
|
title = Column(String)
|
|
archive_datetime = Column(TZDateTime)
|
|
contents = Column(String)
|
|
|
|
textsearch = Column(tsvector, Computed('''setweight(to_tsvector('english'::regconfig, title), 'A') ||
|
|
setweight(to_tsvector('english'::regconfig, contents), 'D')'''))
|
|
|
|
def __repr__(self):
|
|
return f'<Archive id={self.id} url={self.url} singlefile={self.singlefile_path}>'
|
|
|
|
def my_paths(self) -> Generator:
|
|
if self.singlefile_path:
|
|
yield self.singlefile_path.path
|
|
if self.readability_path:
|
|
yield self.readability_path.path
|
|
if self.readability_json_path:
|
|
yield self.readability_json_path.path
|
|
if self.readability_txt_path:
|
|
yield self.readability_txt_path.path
|
|
if self.screenshot_path:
|
|
yield self.screenshot_path.path
|
|
|
|
def unlink(self):
|
|
"""
|
|
Remove any files in this archive.
|
|
"""
|
|
# Don't fail if a file is missing, it could have been deleted manually.
|
|
for path in self.my_paths():
|
|
path.unlink(missing_ok=True)
|
|
|
|
def __gt__(self, other) -> bool:
|
|
"""
|
|
Compare Archives according to their archive datetime.
|
|
"""
|
|
if not isinstance(other, Archive):
|
|
raise ValueError(f'Cannot compare {type(other)} to Archive!')
|
|
|
|
return self.archive_datetime > other.archive_datetime
|
|
|
|
def __json__(self):
|
|
d = dict(
|
|
archive_datetime=self.archive_datetime,
|
|
domain=self.domain.dict() if self.domain else None,
|
|
domain_id=self.domain_id,
|
|
id=self.id,
|
|
readability_json_path=self.readability_json_path,
|
|
readability_path=self.readability_path,
|
|
readability_txt_path=self.readability_txt_path,
|
|
screenshot_path=self.screenshot_path,
|
|
singlefile_path=self.singlefile_path,
|
|
title=self.title,
|
|
url=self.url,
|
|
)
|
|
return d
|
|
|
|
def delete(self):
|
|
self.unlink()
|
|
|
|
session = Session.object_session(self)
|
|
|
|
session.query(Archive).filter_by(id=self.id).delete()
|
|
|
|
if self.domain:
|
|
domain_archives = [i.id for i in self.domain.archives]
|
|
if not domain_archives:
|
|
self.domain.delete()
|
|
|
|
|
|
class Domain(Base, ModelHelper):
|
|
__tablename__ = 'domains' # plural to avoid conflict
|
|
id = Column(Integer, primary_key=True)
|
|
|
|
domain = Column(String)
|
|
directory = Column(MediaPathType)
|
|
|
|
archives: InstrumentedList = relationship('Archive', primaryjoin='Archive.domain_id==Domain.id')
|
|
|
|
def __repr__(self):
|
|
return f'<Domain id={self.id} domain={self.domain} directory={self.directory}>'
|
|
|
|
def delete(self):
|
|
session = Session.object_session(self)
|
|
session.execute('DELETE FROM archive WHERE domain_id=:id', dict(id=self.id))
|
|
session.query(Domain).filter_by(id=self.id).delete()
|