Merge branch 'search'
This commit is contained in:
commit
e00e32dd81
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -1,4 +1,6 @@
|
||||||
|
.vscode/
|
||||||
|
__pycache__/
|
||||||
db.sqlite3
|
db.sqlite3
|
||||||
videos/
|
videos/
|
||||||
channel_archiver/yt-dlp-archive.txt
|
channel_archiver/yt-dlp-archive.txt
|
||||||
channel_archiver/UnusualVideos*
|
channel_archiver/UnusualVideos*
|
||||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"[python]": {
|
|
||||||
"editor.defaultFormatter": "ms-python.python"
|
|
||||||
},
|
|
||||||
"python.formatting.provider": "none"
|
|
||||||
}
|
|
||||||
24
api/README.md
Normal file
24
api/README.md
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# VideoAPI
|
||||||
|
|
||||||
|
## Search
|
||||||
|
`GET /api/?param=value`
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
| Param | Value |
|
||||||
|
|-|-|
|
||||||
|
| `q` | The search query string. |
|
||||||
|
| `limit` | A limit on the number of objects to be returned. Default is 6. |
|
||||||
|
|
||||||
|
### Response
|
||||||
|
```
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Video 1"
|
||||||
|
},
|
||||||
|
{...}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
> `GET /api/?q=foo&limit=3` will return the first 3 videos with "foo" in their name.
|
||||||
0
api/__init__.py
Normal file
0
api/__init__.py
Normal file
7
api/urls.py
Normal file
7
api/urls.py
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
from django.urls import path, include
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('search/', views.searchAPI),
|
||||||
|
path('', include('sage_stream.api.urls')),
|
||||||
|
]
|
||||||
17
api/views.py
Normal file
17
api/views.py
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
from django.db.models import Q
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.decorators import api_view
|
||||||
|
from core.models import Video
|
||||||
|
from core.serializers import VideoSerializer
|
||||||
|
|
||||||
|
@api_view(['GET'])
|
||||||
|
def searchAPI(request):
|
||||||
|
q = request.GET.get('q', '')
|
||||||
|
l = request.GET.get('limit', '6')
|
||||||
|
try:
|
||||||
|
l = int(l)
|
||||||
|
videos = Video.objects.filter(Q(id__contains=q) | Q(name__contains=q))[:l]
|
||||||
|
except:
|
||||||
|
videos = Video.objects.filter(Q(id__contains=q) | Q(name__contains=q))
|
||||||
|
serializer = VideoSerializer(videos, many=True)
|
||||||
|
return Response(serializer.data)
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,6 +1,4 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
|
|
||||||
from .models import Video
|
from .models import Video
|
||||||
|
|
||||||
@admin.register(Video)
|
@admin.register(Video)
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
7
core/serializers.py
Normal file
7
core/serializers.py
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
from rest_framework import serializers
|
||||||
|
from .models import Video
|
||||||
|
|
||||||
|
class VideoSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Video
|
||||||
|
fields = ['id', 'name']
|
||||||
|
|
@ -12,8 +12,7 @@
|
||||||
<link rel="stylesheet" href="{% static 'dist/css/adminlte.css' %}">
|
<link rel="stylesheet" href="{% static 'dist/css/adminlte.css' %}">
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
|
href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet" href="{% static 'plugins/select2/css/select2.min.css' %}">
|
||||||
href="{% static 'plugins/fontawesome-free/css/all.min.css' %}">
|
|
||||||
</head>
|
</head>
|
||||||
<body class="layout-top-nav" style="height: auto;">
|
<body class="layout-top-nav" style="height: auto;">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
|
|
@ -51,12 +50,18 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="float-right" style="width:100%">
|
<div class="float-right" style="width:100%">
|
||||||
|
|
||||||
<form class="form-inline ml-0 ml-md-3 float-right">
|
<form class="form-inline ml-0 ml-md-3 float-right">
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
<input class="form-control form-control-navbar"
|
<input class="form-control form-control-navbar" data-toggle="dropdown"
|
||||||
type="search"
|
type="search"
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
aria-label="Search">
|
aria-label="Search"
|
||||||
|
autocomplete="off"
|
||||||
|
id="search">
|
||||||
|
<ul class="dropdown-menu" id="searchdropdown">
|
||||||
|
<li><span class="dropdown-item-text">Nothing</span></li>
|
||||||
|
</ul>
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<button class="btn btn-navbar" type="submit">
|
<button class="btn btn-navbar" type="submit">
|
||||||
<i class="fas fa-search"></i>
|
<i class="fas fa-search"></i>
|
||||||
|
|
@ -64,6 +69,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -123,5 +129,6 @@
|
||||||
<script src="{% static 'plugins/jquery/jquery.min.js' %}"></script>
|
<script src="{% static 'plugins/jquery/jquery.min.js' %}"></script>
|
||||||
<script src="{% static 'plugins/bootstrap/js/bootstrap.bundle.min.js' %}"></script>
|
<script src="{% static 'plugins/bootstrap/js/bootstrap.bundle.min.js' %}"></script>
|
||||||
<script src="{% static 'dist/js/adminlte.min.js' %}"></script>
|
<script src="{% static 'dist/js/adminlte.min.js' %}"></script>
|
||||||
|
<script src="{% static 'dist/js/searchsuggestions.js' %}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.core, name='core'),
|
path('', views.core, name='core'),
|
||||||
path('status/', views.status, name='status'),
|
path('status/', views.status, name='status'),
|
||||||
path('about/', views.about, name='about'),
|
path('about/', views.about, name='about'),
|
||||||
path('random/', views.random, name='random'),
|
path('random/', views.random, name='random'),
|
||||||
path('view/<int:id>', views.view, name='view'),
|
path('view/<int:id>', views.view, name='view'),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.http import HttpResponse
|
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from core.models import Video
|
from core.models import Video
|
||||||
import random
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
|
|
@ -11,10 +8,9 @@ def core(request):
|
||||||
videos = Video.objects.all()
|
videos = Video.objects.all()
|
||||||
return render(request, 'base.html', {'videos': videos[::-1]})
|
return render(request, 'base.html', {'videos': videos[::-1]})
|
||||||
|
|
||||||
|
|
||||||
def random(request):
|
def random(request):
|
||||||
videos = Video.objects.all().order_by("?")
|
videos = Video.objects.all().order_by("?")
|
||||||
ran = videos.first();
|
ran = videos.first()
|
||||||
return redirect('/view/'+str(ran.id))
|
return redirect('/view/'+str(ran.id))
|
||||||
|
|
||||||
def status(request):
|
def status(request):
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -22,9 +22,7 @@ urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('auth/', include('django.contrib.auth.urls')),
|
path('auth/', include('django.contrib.auth.urls')),
|
||||||
path('', include('core.urls')),
|
path('', include('core.urls')),
|
||||||
path('/', include('core.urls')),
|
path('api/', include('api.urls')),
|
||||||
path('status/', include('core.urls')),
|
|
||||||
path('api/', include('sage_stream.api.urls')),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
|
|
||||||
38
static/dist/js/searchsuggestions.js
vendored
Normal file
38
static/dist/js/searchsuggestions.js
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
const searchinput = document.querySelector("#search");
|
||||||
|
const searchsuggestions = document.querySelector("#searchdropdown");
|
||||||
|
const li = (c) => document.createElement("li").appendChild(c);
|
||||||
|
searchinput.addEventListener("input", (e) => {
|
||||||
|
q(e.target.value).then((d) => {
|
||||||
|
if (d.length < 1) searchsuggestions.replaceChildren(nothing());
|
||||||
|
else searchsuggestions.replaceChildren(...suggestions(d));
|
||||||
|
})
|
||||||
|
});
|
||||||
|
async function q(s) {
|
||||||
|
if (s.length > 0) {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/search/?q=" + s);
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch(error) {
|
||||||
|
console.log("Error: " + error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
function nothing() {
|
||||||
|
const span = document.createElement("span");
|
||||||
|
span.setAttribute("class", "dropdown-item-text");
|
||||||
|
span.insertAdjacentText("afterbegin", "Nothing");
|
||||||
|
return li(span);
|
||||||
|
}
|
||||||
|
function suggestions(d) {
|
||||||
|
const items = [];
|
||||||
|
for (const vid of d) {
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.setAttribute("class", "dropdown-item")
|
||||||
|
a.setAttribute("href", "/view/" + vid.id);
|
||||||
|
a.insertAdjacentText("afterbegin", vid.name + " " + vid.id);
|
||||||
|
items.push(li(a));
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user