diff --git a/docs/Search.md b/docs/Search.md index 2c7717b..f6ad652 100644 --- a/docs/Search.md +++ b/docs/Search.md @@ -1,31 +1,32 @@ # Search Page Accessible at `/search/` of your **Tube Archivist**, search your archive for Videos, Channels and Playlists - or even full text search throughout your indexed subtitles. +Just start typing to start a **simple** search *or* **start your query with a primary keyword** to search for a specific type and narrow down the result with secondary keywords. Secondary keywords can be in any order. Use *yes* or *no* for boolean values. + +- This will return 30 results per query, pagination is not implemented yet. - All your queries are case insensitive and are normalized to lowercase. - All your queries are analyzed for the english language, this means *singular*, *plural* and word variations like *-ing*, *-ed*, *-able* etc are treated as synonyms. +- Keyword value parsing begins with the `keyword:` name all the way until the end of query or the next keyword, e.g. in `video:learn python channel:corey`, the keyword `video` has value `learn python`. - Fuzzy search is activated for all your searches by default. This can catch typos in your queries or in the matching documents with one to two letters difference, depending on the query length. You can configure fuzziness with the secondary keyword `fuzzy:`, e.g: - `fuzzy:0` or `fuzzy:no`: Deactivate fuzzy matching. - `fuzzy:1`: Set fuzziness to one letter difference. - `fuzzy:2`: Set fuzziness to two letters difference. - All text searches are ranked, meaning the better a match the higher ranked the result. Unless otherwise stated, queries with multiple words are processed with the `and` operator, meaning all words need to match so each word will narrow down the result. -- This will return 30 results per query, pagination is not implemented yet. - -Just start typing to start a *simple* search or start your query with a primary keyword to search for a specific type and narrow down the result with secondary keywords. Secondary keywords can be in any order. Use *yes* or *no* for boolean values. ## Simple -Start your query without a keyword to make a simple query. This will search in *video titles*, *channel names* and *playlist titles* and will return matching videos, channels and playlists. Keyword searches will return more results in a particular category due to the fact that more fields are searched for matches. +Start your query without a keyword to make a simple query (primary keyword `simple:` is implied). This will search in *video titles*, *channel names* and *playlist titles* and will return matching videos, channels and playlists. Keyword searches will return more results in a particular category due to the fact that more fields are searched for matches. Simple queries do not have any secondary keywords. ## Video -Start your query with the primary keyword `video:` to search for videos only. This will search through the *video titles*, *tags* and *category* fields. Narrow your search down with secondary keywords: +Start your query with the **primary keyword** `video:` to search for videos only. This will search through the *video titles*, *tags* and *category* fields. Narrow your search down with secondary keywords: - `channel:` search for videos matching the channel name. - `active:` is a boolean value, to search for videos that are still active on youtube or that are not active any more. **Example**: -- `video:learn python channel:corey shafer active:yes`: This will return all videos with the term *Learn Python* from the channel *Corey Shafer* that are still *Active* on YouTube. +- `video:learn python channel:corey schafer active:yes`: This will return all videos with the term *Learn Python* from the channel *Corey Schafer* that are still *Active* on YouTube. - `video: channel:tom scott active:no`: Note the omitted term after the primary key, this will show all videos from the channel *Tom Scott* that are no longer active on YouTube. ## Channel -Start with the `channel:` primary keyword to search for channels matching your query. This will search through the *channel name* and *channel description* fields. Narrow your search down with secondary keywords: +Start with the `channel:` **primary keyword** to search for channels matching your query. This will search through the *channel name* and *channel description* fields. Narrow your search down with secondary keywords: - `subscribed:` is a boolean value, search for channels that you are subscribed to or not. - `active:` is a boolean value, to search for channels that are still active on YouTube or that are no longer active. @@ -34,7 +35,7 @@ Start with the `channel:` primary keyword to search for channels matching your q - `channel: active:no`: Note the omitted term after the primary key, this will return all channels that are no longer active on YouTube. ## Playlist -Start your query with the primary keyword `playlist:` to search for playlists only. This will search through the *playlist title* and *playlist description* fields. Narrow down your search with these secondary keywords: +Start your query with the **primary keyword** `playlist:` to search for playlists only. This will search through the *playlist title* and *playlist description* fields. Narrow down your search with these secondary keywords: - `subscribed`: is a boolean value, search for playlists that you are subscribed to or not. - `active:` is a boolean value, to search for playlists that are still active on YouTube or that are no longer active. @@ -44,7 +45,7 @@ Start your query with the primary keyword `playlist:` to search for playlists on - `playlist:html css active:yes`: Search for playlists containing *HTML CSS* that are still active on YouTube. ## Full -Start a full text search by beginning your query with the primary keyword `full:`. This will search through your indexed Subtitles showing segments with possible matches. This will only show any results if you have activated *subtitle download and index* on the settings page. The operator for full text searches is `or` meaning when searching for multiple words not all words need to match, but additional words will change the ranking of the result, the more words match and the better they match, the higher ranked the result. The matching words will get highlighted in the text preview. +Start a full text search by beginning your query with the **primary keyword** `full:`. This will search through your indexed Subtitles showing segments with possible matches. This will only show any results if you have activated *subtitle download and index* on the settings page. The operator for full text searches is `or` meaning when searching for multiple words not all words need to match, but additional words will change the ranking of the result, the more words match and the better they match, the higher ranked the result. The matching words will get highlighted in the text preview. Clicking the play button on the thumbnail will open the inplace player at the timestamp from where the segment starts. Same when clicking the video title, this will open the video page and put the player at the segment timestamp. This will overwrite any previous playback position. diff --git a/tubearchivist/home/templates/home/search.html b/tubearchivist/home/templates/home/search.html index b333baa..5bbfe15 100644 --- a/tubearchivist/home/templates/home/search.html +++ b/tubearchivist/home/templates/home/search.html @@ -7,30 +7,80 @@ -
-

Video Results

-
-

No videos found.

+ -
-

Channel Results

-
-

No channels found.

+
+
+

Example queries

+
    +
  • music video — basic search
  • +
  • video: active:no — all videos deleted from YouTube
  • +
  • video:learn javascript channel:corey schafer active:yes
  • +
  • channel:linux subscribed:yes
  • +
  • playlist:backend engineering active:yes subscribed:yes
  • +
-
-
-

Playlist Results

-
-

No playlists found.

-
-
-
-

Fulltext Results

-
-

No fulltext results found.

+
+

Keywords cheatsheet

+

For detailed usage check wiki.

+
+
    +
  • simple: (implied) — search in video titles, channel names and playlist titles
  • +
  • + video: — search in video titles, tags and category field +
      +
    • channel: — channel name
    • +
    • active:yes/no — whether the video is still active on YouTube
    • +
    +
  • +
  • + channel: — search in channel name and channel description +
      +
    • subscribed:yes/no — whether you are subscribed to the channel
    • +
    • active:yes/no — whether the video is still active on YouTube
    • +
    +
  • +
  • + playlist: — search in channel name and channel description +
      +
    • subscribed:yes/no — whether you are subscribed to the channel
    • +
    • active:yes/no — whether the video is still active on YouTube
    • +
    +
  • +
  • + full: — search in video subtitles +
      +
    • lang: — subtitles language (use two-letter ISO country code, same as the one from settings page)
    • +
    • source:auto/userauto to search though auto-generated subtitles only, or user to search through user-uploaded subtitles only
    • +
    +
  • +
+
diff --git a/tubearchivist/static/css/style.css b/tubearchivist/static/css/style.css index 56ab4e3..dbf76f9 100644 --- a/tubearchivist/static/css/style.css +++ b/tubearchivist/static/css/style.css @@ -892,10 +892,24 @@ video:-webkit-full-screen { width: 100%; } -.multi-search-result { +.multi-search-result, #multi-search-results-placeholder { padding: 1rem 0; } +#multi-search-results-placeholder span { + font-family: monospace; + color: var(--accent-font-dark); + background-color: var(--highlight-bg); +} + +#multi-search-results-placeholder span.value { + color: var(--accent-font-light); +} + +#multi-search-results-placeholder ul { + margin-top: 10px; +} + /* channel overview page */ .channel-list.list { display: block; diff --git a/tubearchivist/static/script.js b/tubearchivist/static/script.js index 8dfff95..ff8e8cc 100644 --- a/tubearchivist/static/script.js +++ b/tubearchivist/static/script.js @@ -865,21 +865,33 @@ function setProgressBar(videoId, currentTime, duration) { // multi search form let searchTimeout = null; +let searchHttpRequest = null; function searchMulti(query) { clearTimeout(searchTimeout); searchTimeout = setTimeout(function () { - if (query.length > 1) { - let http = new XMLHttpRequest(); - http.onreadystatechange = function () { - if (http.readyState === 4) { - let response = JSON.parse(http.response); + if (query.length > 0) { + if (searchHttpRequest) { + searchHttpRequest.abort(); + } + searchHttpRequest = new XMLHttpRequest(); + searchHttpRequest.onreadystatechange = function () { + if (searchHttpRequest.readyState === 4) { + const response = JSON.parse(searchHttpRequest.response); populateMultiSearchResults(response.results, response.queryType); } }; - http.open('GET', `/api/search/?query=${query}`, true); - http.setRequestHeader('X-CSRFToken', getCookie('csrftoken')); - http.setRequestHeader('Content-type', 'application/json'); - http.send(); + searchHttpRequest.open('GET', `/api/search/?query=${query}`, true); + searchHttpRequest.setRequestHeader('X-CSRFToken', getCookie('csrftoken')); + searchHttpRequest.setRequestHeader('Content-type', 'application/json'); + searchHttpRequest.send(); + } else { + if (searchHttpRequest) { + searchHttpRequest.abort(); + searchHttpRequest = null; + } + // show the placeholder container and hide the results container + document.getElementById('multi-search-results').style.display = 'none'; + document.getElementById('multi-search-results-placeholder').style.display = 'block'; } }, 500); } @@ -890,6 +902,9 @@ function getViewDefaults(view) { } function populateMultiSearchResults(allResults, queryType) { + // show the results container and hide the placeholder container + document.getElementById('multi-search-results').style.display = 'block'; + document.getElementById('multi-search-results-placeholder').style.display = 'none'; // videos let defaultVideo = getViewDefaults('home'); let allVideos = allResults.video_results;