implement fulltext search keyword

This commit is contained in:
simon 2022-07-20 21:49:32 +07:00
parent eb5a7338ab
commit e4dd47aed0
No known key found for this signature in database
GPG Key ID: 2C15AA5E89985DD4
4 changed files with 113 additions and 2 deletions

View File

@ -136,6 +136,11 @@ class SearchHandler:
date_str = datetime.strftime(date_refresh, "%d %b, %Y")
hit["source"]["channel"]["channel_last_refresh"] = date_str
if "subtitle_fragment_id" in hit_keys:
youtube_id = hit["source"]["youtube_id"]
thumb_path = ThumbManager().vid_thumb_path(youtube_id)
hit["source"]["vid_thumb_url"] = f"/cache/{thumb_path}"
return hit
@ -159,6 +164,7 @@ class SearchForm:
video_results = []
channel_results = []
playlist_results = []
fulltext_results = []
if search_results:
for result in search_results:
if result["_index"] == "ta_video":
@ -167,11 +173,14 @@ class SearchForm:
channel_results.append(result)
elif result["_index"] == "ta_playlist":
playlist_results.append(result)
elif result["_index"] == "ta_subtitle":
fulltext_results.append(result)
all_results = {
"video_results": video_results,
"channel_results": channel_results,
"playlist_results": playlist_results,
"fulltext_results": fulltext_results,
}
return all_results
@ -240,7 +249,7 @@ class SearchParser:
"active": [],
"subscribed": [],
},
"all": {
"full": {
"index": "ta_subtitle",
"term": [],
},
@ -303,11 +312,18 @@ class QueryBuilder:
"video": self._build_video,
"channel": self._build_channel,
"playlist": self._build_playlist,
"full": self._build_fulltext,
}
build_must_list = exec_map[self.query_type]
query = {"size": 30, "query": {"bool": {"must": build_must_list()}}}
if self.query_type == "full":
query = build_must_list()
else:
query = {
"size": 30,
"query": {"bool": {"must": build_must_list()}},
}
return query
@ -448,3 +464,36 @@ class QueryBuilder:
)
return must_list
def _build_fulltext(self):
"""build query for fulltext search"""
must_list = []
if (term := self.query_map.get("term")) is not None:
must_list.append(
{
"match": {
"subtitle_line": {
"query": term,
"fuzziness": "auto",
}
}
}
)
query = {
"size": 30,
"_source": {"excludes": "subtitle_line"},
"query": {"bool": {"must": must_list}},
"highlight": {
"fields": {
"subtitle_line": {
"number_of_fragments": 0,
"pre_tags": ['<span class="settings-current">'],
"post_tags": ["</span>"],
}
}
},
}
return query

View File

@ -26,5 +26,11 @@
<p>No playlists found.</p>
</div>
</div>
<div class="multi-search-result">
<h2>Fulltext Results</h2>
<div id="fulltext-results" class="video-list list">
<p>No fulltext results found.</p>
</div>
</div>
</div>
{% endblock content %}

View File

@ -781,6 +781,10 @@ button:hover {
}
/* multi search page */
.multi-search-box {
padding-right: 20px;
}
.multi-search-box input {
width: 100%;
}

View File

@ -869,6 +869,24 @@ function populateMultiSearchResults(allResults, queryType) {
playlistBox.parentElement.style.display = "none";
}
}
// fulltext
var allFullText = allResults.fulltext_results;
var fullTextBox = document.getElementById("fulltext-results");
fullTextBox.innerHTML = "";
fullTextBox.parentElement.style.display = "block";
if (allFullText.length > 0) {
for (let i = 0; i < allFullText.length; i++) {
const fullText = allFullText[i];
const fullTextDiv = createFulltext(fullText);
fullTextBox.appendChild(fullTextDiv);
}
} else {
if (queryType === "simple" || queryType == "full") {
fullTextBox.innerHTML = "<p>No fulltext items found.</p>";
} else {
fullTextBox.parentElement.style.display = "none";
}
}
}
@ -992,6 +1010,40 @@ function createPlaylist(playlist, viewStyle) {
return playlistDiv;
}
function createFulltext(fullText) {
const videoId = fullText.source.youtube_id;
const videoTitle = fullText.source.title;
const thumbUrl = fullText.source.vid_thumb_url;
const channelId = fullText.source.subtitle_channel_id;
const channelName = fullText.source.subtitle_channel;
const subtitleLine = fullText.highlight.subtitle_line[0];
const subtitle_start = fullText.source.subtitle_start.split(".")[0];
const subtitle_end = fullText.source.subtitle_end.split(".")[0];
const markup = `
<a href="#player" data-id="${videoId}" onclick="createPlayer(this)">
<div class="video-thumb-wrap list">
<div class="video-thumb">
<img src="${thumbUrl}" alt="video-thumb">
</div>
<div class="video-play">
<img src="/static/img/icon-play.svg" alt="play-icon">
</div>
</div>
</a>
<div class="video-desc list">
<p>${subtitle_start} - ${subtitle_end}</p>
<p>${subtitleLine}</p>
<div>
<a href="/channel/${channelId}/"><h3>${channelName}</h3></a>
<a class="video-more" href="/video/${videoId}/"><h2>${videoTitle}</h2></a>
</div>
</div>
`
const fullTextDiv = document.createElement("div");
fullTextDiv.setAttribute("class", "video-item list");
fullTextDiv.innerHTML = markup;
return fullTextDiv
}
// generic