thejagstudio commited on
Commit
413f1ae
·
verified ·
1 Parent(s): a8df994

Upload 99 files

Browse files
Files changed (47) hide show
  1. CloudStorage/__init__.py +0 -0
  2. CloudStorage/__pycache__/__init__.cpython-311.pyc +0 -0
  3. CloudStorage/__pycache__/__init__.cpython-312.pyc +0 -0
  4. CloudStorage/__pycache__/__init__.cpython-313.pyc +0 -0
  5. CloudStorage/__pycache__/__init__.cpython-39.pyc +0 -0
  6. CloudStorage/__pycache__/settings.cpython-311.pyc +0 -0
  7. CloudStorage/__pycache__/settings.cpython-312.pyc +0 -0
  8. CloudStorage/__pycache__/settings.cpython-313.pyc +0 -0
  9. CloudStorage/__pycache__/settings.cpython-39.pyc +0 -0
  10. CloudStorage/__pycache__/urls.cpython-311.pyc +0 -0
  11. CloudStorage/__pycache__/urls.cpython-312.pyc +0 -0
  12. CloudStorage/__pycache__/urls.cpython-39.pyc +0 -0
  13. CloudStorage/__pycache__/wsgi.cpython-311.pyc +0 -0
  14. CloudStorage/__pycache__/wsgi.cpython-312.pyc +0 -0
  15. CloudStorage/__pycache__/wsgi.cpython-39.pyc +0 -0
  16. CloudStorage/asgi.py +16 -0
  17. CloudStorage/settings.py +145 -0
  18. CloudStorage/urls.py +24 -0
  19. CloudStorage/wsgi.py +16 -0
  20. home/__pycache__/__init__.cpython-312.pyc +0 -0
  21. home/__pycache__/__init__.cpython-313.pyc +0 -0
  22. home/__pycache__/admin.cpython-312.pyc +0 -0
  23. home/__pycache__/apps.cpython-312.pyc +0 -0
  24. home/__pycache__/apps.cpython-313.pyc +0 -0
  25. home/__pycache__/models.cpython-312.pyc +0 -0
  26. home/__pycache__/urls.cpython-312.pyc +0 -0
  27. home/__pycache__/views.cpython-312.pyc +0 -0
  28. home/migrations/0011_movies_backdrop.py +18 -0
  29. home/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
  30. home/migrations/__pycache__/0002_rename_data_userdata.cpython-312.pyc +0 -0
  31. home/migrations/__pycache__/0003_userdata_ip.cpython-312.pyc +0 -0
  32. home/migrations/__pycache__/0004_ip_address_remove_userdata_ip.cpython-312.pyc +0 -0
  33. home/migrations/__pycache__/0005_remove_userdata_files.cpython-312.pyc +0 -0
  34. home/migrations/__pycache__/0006_movies.cpython-312.pyc +0 -0
  35. home/migrations/__pycache__/0007_movies_uploaded.cpython-312.pyc +0 -0
  36. home/migrations/__pycache__/0008_movies_casts_movies_country_movies_duration_and_more.cpython-312.pyc +0 -0
  37. home/migrations/__pycache__/0009_movies_imdbid.cpython-312.pyc +0 -0
  38. home/migrations/__pycache__/0010_alter_movies_casts_alter_movies_country_and_more.cpython-312.pyc +0 -0
  39. home/migrations/__pycache__/0011_movies_backdrop.cpython-312.pyc +0 -0
  40. home/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
  41. home/models.py +1 -0
  42. home/movies.json +0 -0
  43. home/urls.py +23 -21
  44. home/views.py +482 -327
  45. templates/godMode.html +77 -77
  46. templates/movie.html +51 -72
  47. templates/movieDetail.html +199 -156
CloudStorage/__init__.py ADDED
File without changes
CloudStorage/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (177 Bytes). View file
 
CloudStorage/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (144 Bytes). View file
 
CloudStorage/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (144 Bytes). View file
 
CloudStorage/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (156 Bytes). View file
 
CloudStorage/__pycache__/settings.cpython-311.pyc ADDED
Binary file (3.1 kB). View file
 
CloudStorage/__pycache__/settings.cpython-312.pyc ADDED
Binary file (3.01 kB). View file
 
CloudStorage/__pycache__/settings.cpython-313.pyc ADDED
Binary file (3.01 kB). View file
 
CloudStorage/__pycache__/settings.cpython-39.pyc ADDED
Binary file (2.88 kB). View file
 
CloudStorage/__pycache__/urls.cpython-311.pyc ADDED
Binary file (1.41 kB). View file
 
CloudStorage/__pycache__/urls.cpython-312.pyc ADDED
Binary file (1.31 kB). View file
 
CloudStorage/__pycache__/urls.cpython-39.pyc ADDED
Binary file (1.08 kB). View file
 
CloudStorage/__pycache__/wsgi.cpython-311.pyc ADDED
Binary file (709 Bytes). View file
 
CloudStorage/__pycache__/wsgi.cpython-312.pyc ADDED
Binary file (642 Bytes). View file
 
CloudStorage/__pycache__/wsgi.cpython-39.pyc ADDED
Binary file (569 Bytes). View file
 
CloudStorage/asgi.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ASGI config for CloudStorage project.
3
+
4
+ It exposes the ASGI callable as a module-level variable named ``application``.
5
+
6
+ For more information on this file, see
7
+ https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/
8
+ """
9
+
10
+ import os
11
+
12
+ from django.core.asgi import get_asgi_application
13
+
14
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CloudStorage.settings')
15
+
16
+ application = get_asgi_application()
CloudStorage/settings.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Django settings for CloudStorage project.
3
+
4
+ Generated by 'django-admin startproject' using Django 4.0.4.
5
+
6
+ For more information on this file, see
7
+ https://docs.djangoproject.com/en/4.0/topics/settings/
8
+
9
+ For the full list of settings and their values, see
10
+ https://docs.djangoproject.com/en/4.0/ref/settings/
11
+ """
12
+
13
+ from pathlib import Path
14
+ import os
15
+
16
+ # Build paths inside the project like this: BASE_DIR / 'subdir'.
17
+ BASE_DIR = Path(__file__).resolve().parent.parent
18
+
19
+
20
+ # Quick-start development settings - unsuitable for production
21
+ # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
22
+
23
+ # SECURITY WARNING: keep the secret key used in production secret!
24
+ SECRET_KEY = 'django-insecure-f221fh+#lk4ul5x@gk7bm2x5f&+u3uhu+t-(bri%t(uh!z6gf#'
25
+
26
+ # SECURITY WARNING: don't run with debug turned on in production!
27
+ DEBUG = True
28
+ X_FRAME_OPTIONS = 'ALLOWALL'
29
+
30
+ ALLOWED_HOSTS = ['127.0.0.1', 'thejagstudio-cloudstorage.hf.space']
31
+ CORS_ALLOWED_ORIGINS = [
32
+ 'https://thejagstudio-cloudstorage.hf.space',
33
+ 'https://huggingface.co'
34
+ ]
35
+ CORS_ALLOW_ALL_ORIGINS = True
36
+
37
+
38
+ # Application definition
39
+
40
+ INSTALLED_APPS = [
41
+ 'django.contrib.admin',
42
+ 'django.contrib.auth',
43
+ 'django.contrib.contenttypes',
44
+ 'django.contrib.sessions',
45
+ 'django.contrib.messages',
46
+ 'django.contrib.staticfiles',
47
+ 'home',
48
+ 'corsheaders'
49
+ ]
50
+
51
+ MIDDLEWARE = [
52
+ 'django.middleware.security.SecurityMiddleware',
53
+ 'django.contrib.sessions.middleware.SessionMiddleware',
54
+ 'django.middleware.common.CommonMiddleware',
55
+ 'django.middleware.csrf.CsrfViewMiddleware',
56
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
57
+ 'django.contrib.messages.middleware.MessageMiddleware',
58
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
59
+ ]
60
+
61
+ ROOT_URLCONF = 'CloudStorage.urls'
62
+
63
+ TEMPLATES = [
64
+ {
65
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
66
+ 'DIRS': ['templates'],
67
+ 'APP_DIRS': True,
68
+ 'OPTIONS': {
69
+ 'context_processors': [
70
+ 'django.template.context_processors.debug',
71
+ 'django.template.context_processors.request',
72
+ 'django.contrib.auth.context_processors.auth',
73
+ 'django.contrib.messages.context_processors.messages',
74
+ ],
75
+ },
76
+ },
77
+ ]
78
+
79
+ WSGI_APPLICATION = 'CloudStorage.wsgi.application'
80
+
81
+
82
+ # Database
83
+ # https://docs.djangoproject.com/en/4.0/ref/settings/#databases
84
+
85
+ DATABASES = {
86
+ 'default': {
87
+ 'ENGINE': 'django.db.backends.postgresql',
88
+ 'NAME': 'postgres',
89
+ 'USER': 'postgres.ptkwerplskfglvudefxq',
90
+ 'PORT': 5432,
91
+ 'PASSWORD': 'KBIPUBbDVDdiftJf',
92
+ 'HOST': 'aws-0-us-east-2.pooler.supabase.com',
93
+ }
94
+ }
95
+ # DATABASES = {
96
+ # 'default': {
97
+ # 'ENGINE': 'django.db.backends.sqlite3',
98
+ # 'NAME': BASE_DIR / 'db.sqlite3',
99
+ # }
100
+ # }
101
+
102
+
103
+ # Password validation
104
+ # https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
105
+
106
+ AUTH_PASSWORD_VALIDATORS = [
107
+ {
108
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
109
+ },
110
+ {
111
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
112
+ },
113
+ {
114
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
115
+ },
116
+ {
117
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
118
+ },
119
+ ]
120
+
121
+
122
+ # Internationalization
123
+ # https://docs.djangoproject.com/en/4.0/topics/i18n/
124
+
125
+ LANGUAGE_CODE = 'en-us'
126
+
127
+ TIME_ZONE = 'UTC'
128
+
129
+ USE_I18N = True
130
+
131
+ USE_TZ = True
132
+
133
+
134
+ # Static files (CSS, JavaScript, Images)
135
+ # https://docs.djangoproject.com/en/4.0/howto/static-files/
136
+
137
+ STATIC_URL = '/static/'
138
+ STATICFILES_DIRS = [
139
+ BASE_DIR / "static",
140
+ ]
141
+
142
+ # Default primary key field type
143
+ # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
144
+
145
+ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
CloudStorage/urls.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """CloudStorage URL Configuration
2
+
3
+ The `urlpatterns` list routes URLs to views. For more information please see:
4
+ https://docs.djangoproject.com/en/4.0/topics/http/urls/
5
+ Examples:
6
+ Function views
7
+ 1. Add an import: from my_app import views
8
+ 2. Add a URL to urlpatterns: path('', views.home, name='home')
9
+ Class-based views
10
+ 1. Add an import: from other_app.views import Home
11
+ 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12
+ Including another URLconf
13
+ 1. Import the include() function: from django.urls import include, path
14
+ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15
+ """
16
+ from django.contrib import admin
17
+ from django.urls import path, include
18
+ from django.conf import settings
19
+ from django.conf.urls.static import static
20
+
21
+ urlpatterns = [
22
+ path('admin/', admin.site.urls),
23
+ path('', include('home.urls')),
24
+ ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
CloudStorage/wsgi.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ WSGI config for CloudStorage project.
3
+
4
+ It exposes the WSGI callable as a module-level variable named ``application``.
5
+
6
+ For more information on this file, see
7
+ https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/
8
+ """
9
+
10
+ import os
11
+
12
+ from django.core.wsgi import get_wsgi_application
13
+
14
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CloudStorage.settings')
15
+
16
+ application = get_wsgi_application()
home/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (136 Bytes). View file
 
home/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (136 Bytes). View file
 
home/__pycache__/admin.cpython-312.pyc ADDED
Binary file (609 Bytes). View file
 
home/__pycache__/apps.cpython-312.pyc ADDED
Binary file (438 Bytes). View file
 
home/__pycache__/apps.cpython-313.pyc ADDED
Binary file (496 Bytes). View file
 
home/__pycache__/models.cpython-312.pyc ADDED
Binary file (2.35 kB). View file
 
home/__pycache__/urls.cpython-312.pyc ADDED
Binary file (1.78 kB). View file
 
home/__pycache__/views.cpython-312.pyc ADDED
Binary file (30 kB). View file
 
home/migrations/0011_movies_backdrop.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Generated by Django 5.0.2 on 2025-06-06 17:07
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("home", "0010_alter_movies_casts_alter_movies_country_and_more"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name="movies",
15
+ name="backdrop",
16
+ field=models.CharField(default="", max_length=1000, null=True),
17
+ ),
18
+ ]
home/migrations/__pycache__/0001_initial.cpython-312.pyc ADDED
Binary file (1.4 kB). View file
 
home/migrations/__pycache__/0002_rename_data_userdata.cpython-312.pyc ADDED
Binary file (774 Bytes). View file
 
home/migrations/__pycache__/0003_userdata_ip.cpython-312.pyc ADDED
Binary file (732 Bytes). View file
 
home/migrations/__pycache__/0004_ip_address_remove_userdata_ip.cpython-312.pyc ADDED
Binary file (1.01 kB). View file
 
home/migrations/__pycache__/0005_remove_userdata_files.cpython-312.pyc ADDED
Binary file (629 Bytes). View file
 
home/migrations/__pycache__/0006_movies.cpython-312.pyc ADDED
Binary file (1.1 kB). View file
 
home/migrations/__pycache__/0007_movies_uploaded.cpython-312.pyc ADDED
Binary file (705 Bytes). View file
 
home/migrations/__pycache__/0008_movies_casts_movies_country_movies_duration_and_more.cpython-312.pyc ADDED
Binary file (1.79 kB). View file
 
home/migrations/__pycache__/0009_movies_imdbid.cpython-312.pyc ADDED
Binary file (766 Bytes). View file
 
home/migrations/__pycache__/0010_alter_movies_casts_alter_movies_country_and_more.cpython-312.pyc ADDED
Binary file (2.64 kB). View file
 
home/migrations/__pycache__/0011_movies_backdrop.cpython-312.pyc ADDED
Binary file (780 Bytes). View file
 
home/migrations/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (147 Bytes). View file
 
home/models.py CHANGED
@@ -14,6 +14,7 @@ class ip_address(models.Model):
14
  class movies(models.Model):
15
  movie = models.CharField(max_length=1000, null=True)
16
  poster = models.CharField(max_length=1000, default="", null=True)
 
17
  trailer = models.CharField(max_length=1000, default="", null=True)
18
  description = models.CharField(max_length=1000, default="", null=True)
19
  Released = models.CharField(max_length=1000, default="", null=True)
 
14
  class movies(models.Model):
15
  movie = models.CharField(max_length=1000, null=True)
16
  poster = models.CharField(max_length=1000, default="", null=True)
17
+ backdrop = models.CharField(max_length=1000, default="", null=True)
18
  trailer = models.CharField(max_length=1000, default="", null=True)
19
  description = models.CharField(max_length=1000, default="", null=True)
20
  Released = models.CharField(max_length=1000, default="", null=True)
home/movies.json ADDED
The diff for this file is too large to render. See raw diff
 
home/urls.py CHANGED
@@ -1,21 +1,23 @@
1
- from django.urls import path, re_path
2
- from . import views
3
-
4
- urlpatterns = [
5
- path('', views.index, name="index"),
6
- path('login/', views.user_login, name="user_login"),
7
- path('signup/', views.sign_up, name="sign_up"),
8
- path('logout/', views.user_logout, name="user_logout"),
9
- path('upload/', views.upload, name="upload"),
10
- path('uploader/', views.uploader, name="uploader"),
11
- path('uploaderAI/', views.uploaderAI, name="uploaderAI"),
12
- path('list/', views.list, name="list"),
13
- path('list/<str:id>/', views.folder_list, name="folder_list"),
14
- path('deleteFile/', views.deleteFile, name="deleteFile"),
15
- path('renameFile/', views.renameFile, name="renameFile"),
16
- path('ip/', views.ipGetter, name="ipGetter"),
17
- path('godmode/', views.godMode, name="godMode"),
18
- path('movieDownloader/', views.movieDownloader, name="movieDownloader"),
19
- path('movie/', views.movie, name="movie"),
20
- path('movie/<str:id>', views.movieDetail, name="movieDetail"),
21
- ]
 
 
 
1
+ from django.urls import path, re_path
2
+ from . import views
3
+
4
+ urlpatterns = [
5
+ path('', views.index, name="index"),
6
+ path('login/', views.user_login, name="user_login"),
7
+ path('signup/', views.sign_up, name="sign_up"),
8
+ path('logout/', views.user_logout, name="user_logout"),
9
+ path('upload/', views.upload, name="upload"),
10
+ path('uploader/', views.uploader, name="uploader"),
11
+ path('uploaderAI/', views.uploaderAI, name="uploaderAI"),
12
+ path('list/', views.list, name="list"),
13
+ path('list/<str:id>/', views.folder_list, name="folder_list"),
14
+ path('deleteFile/', views.deleteFile, name="deleteFile"),
15
+ path('renameFile/', views.renameFile, name="renameFile"),
16
+ path('ip/', views.ipGetter, name="ipGetter"),
17
+ path('godmode/', views.godMode, name="godMode"),
18
+ path('movieDownloader/', views.movieDownloader, name="movieDownloader"),
19
+ path('movie/', views.movie, name="movie"),
20
+ path('movie/<str:id>', views.movieDetail, name="movieDetail"),
21
+ path('movieLoader/', views.movieLoader, name="movieLoader"),
22
+ path('movieInputer/', views.movieInputer, name="movieInputer"),
23
+ ]
home/views.py CHANGED
@@ -1,327 +1,482 @@
1
- from django.shortcuts import render, redirect, HttpResponse
2
- from django.contrib.auth import authenticate, login, logout
3
- from django.contrib import messages
4
- from django.contrib.auth.decorators import login_required
5
- from django.contrib.auth.models import User
6
- import json
7
- from .models import Userdata, ip_address, movies
8
- import threading
9
- from django.conf import settings
10
- from django.views.decorators.csrf import csrf_exempt, csrf_protect
11
- from django.core.mail import send_mail
12
- import os
13
- from pydrive.auth import GoogleAuth
14
- from pydrive.drive import GoogleDrive
15
- import requests
16
- import geocoder
17
- import folium
18
- from oauth2client import client
19
- import time
20
-
21
- gauth = GoogleAuth()
22
- content = '{"access_token": "ya29.a0AXooCgtLK5HzYMtRs4R9J7FRZSGR3i5jUkeMeVhGjorlrgq_BupFi8d9upA2skYC5FofxUqo23Nivk_P_Hy8eRn0DWM3deSKoiWMhA3lsy05JVakD0vd2fPRaFOXfRV20jAEGt6ql9yy_0up3Y9z8u9yXZ28IUxRRZAHaCgYKASQSARISFQHGX2MipVyGD4fFFZJWXGvyd-sJnQ0171", "client_id": "895306463817-h14aujg3ohgptue5safg2d81530qs4c3.apps.googleusercontent.com", "client_secret": "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", "refresh_token": "1//0gsu0CorccmScCgYIARAAGBASNwF-L9IrF-TDYDXR_MTQGAGGf4fY4BBBSBUipsz_7c0B6HjmRYZV3uxPVU4CAJjqWoWBm0T4pxA", "token_expiry": "2024-05-25T11:14:56Z", "token_uri": "https://oauth2.googleapis.com/token", "user_agent": null, "revoke_uri": "https://oauth2.googleapis.com/revoke", "id_token": null, "id_token_jwt": null, "token_response": {"access_token": "ya29.a0AXooCgtLK5HzYMtRs4R9J7FRZSGR3i5jUkeMeVhGjorlrgq_BupFi8d9upA2skYC5FofxUqo23Nivk_P_Hy8eRn0DWM3deSKoiWMhA3lsy05JVakD0vd2fPRaFOXfRV20jAEGt6ql9yy_0up3Y9z8u9yXZ28IUxRRZAHaCgYKASQSARISFQHGX2MipVyGD4fFFZJWXGvyd-sJnQ0171", "expires_in": 3599, "refresh_token": "1//0gsu0CorccmScCgYIARAAGBASNwF-L9IrF-TDYDXR_MTQGAGGf4fY4BBBSBUipsz_7c0B6HjmRYZV3uxPVU4CAJjqWoWBm0T4pxA", "scope": "https://www.googleapis.com/auth/drive", "token_type": "Bearer"}, "scopes": ["https://www.googleapis.com/auth/drive"], "token_info_uri": "https://oauth2.googleapis.com/tokeninfo", "invalid": false, "_class": "OAuth2Credentials", "_module": "oauth2client.client"}'
23
- gauth.credentials = client.Credentials.new_from_json(content)
24
- if gauth.access_token_expired:
25
- # Refresh them if expired
26
- gauth.Refresh()
27
- else:
28
- gauth.Authorize()
29
- DRIVE = GoogleDrive(gauth)
30
-
31
-
32
- def GoogleDriveUpload(filename, folder, file):
33
- file1 = DRIVE.CreateFile({'title': filename, 'parents': [{'id': folder}]})
34
- file1.content = file
35
- file1.Upload()
36
-
37
-
38
- @csrf_exempt
39
- def index(request):
40
- context = {
41
- 'user': request.user
42
- }
43
- return render(request, 'index.html', context=context)
44
-
45
-
46
- @csrf_exempt
47
- def movie(request):
48
- all_movies = movies.objects.all()
49
- context = {
50
- 'movies': all_movies.values()
51
- }
52
- return render(request, 'movie.html', context=context)
53
-
54
-
55
- @csrf_exempt
56
- def movieDetail(request, id):
57
-
58
- url = "https://api.themoviedb.org/3/movie/"+id+"?append_to_response=images,reviews,similar,recommendations,credits"
59
- headers = {
60
- 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI2MmY0Njg4NDE4ODI2MDNjODc1Y2EwZDMyMzE1NzkyZSIsInN1YiI6IjYyMDBlNmFmMWZkMzZmMDA2NmI5OTczNSIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.mt_t8wqYYl5b8AlDy5npgiF7sbb8ZaDh_XPauDgMt8I',
61
- 'accept': 'application/json'
62
- }
63
-
64
- response = requests.request("GET", url, headers=headers)
65
- data = response.json()
66
- try:
67
- movie = movies.objects.filter(tmdbId=id).first()
68
- data["driveLink"] = movie.driveLink
69
- url = "https://drive.google.com/get_video_info?docid="+movie.driveLink + "&drive_originator_app=303"
70
-
71
- response = requests.request("GET", url, headers=headers)
72
- urlData = response.text
73
- parsed_url = urlparse("https://drive.google.com/?"+urlData)
74
- urlData = json.loads(parse_qs(parsed_url.query)["player_response"][0])
75
- data["watchLink"] = urlData
76
- except Exception as e:
77
- print(e)
78
-
79
- context = {
80
- 'data': data
81
- }
82
- return render(request, 'movieDetail.html', context=context)
83
-
84
- @csrf_exempt
85
- def user_login(request):
86
- if request.method == 'POST':
87
- username = request.POST['username']
88
- password = request.POST['password']
89
- user = authenticate(request, username=username, password=password)
90
- if user is not None:
91
- login(request, user)
92
- messages.success(request, ('You have been logged in!'))
93
- # print('logged in')
94
- return redirect('index')
95
- else:
96
- messages.success(request, ('Error logging in - please try again.'))
97
- # print('error logging in')
98
- return render(request, 'login.html')
99
- return render(request, 'login.html')
100
-
101
-
102
- @csrf_exempt
103
- def sign_up(request):
104
- if request.method == 'POST':
105
- name = request.POST['name']
106
- email = request.POST['email']
107
- password = request.POST['password']
108
- password2 = request.POST['password1']
109
- user = authenticate(request, email=email, password=password)
110
- if user is not None and password == password2:
111
- login(request, user)
112
- messages.success(request, ('You have been logged in!'))
113
- # print('logged in')
114
- return redirect('index')
115
- elif user is None and password == password2:
116
- user = User.objects.create_user(username=email, email=email, password=password, first_name=name)
117
- user.save()
118
- messages.success(request, ('Created new user!'))
119
- login(request, user)
120
- folder = '1N3uD81zuXY_23esOFWRvN2Fp4zEbCrzy'
121
- new_folder = DRIVE.CreateFile({'title': name, 'mimeType': 'application/vnd.google-apps.folder', 'parents': [{'id': folder}]})
122
- new_folder.Upload()
123
- new_folder.InsertPermission({'type': 'user', 'value': email, 'role': 'writer'})
124
- dataObj = Userdata(user_id=request.user, folder=new_folder['id'])
125
- dataObj.save()
126
- # print('new user created')
127
- return redirect('index')
128
- else:
129
- pass
130
- return render(request, 'signup.html')
131
-
132
-
133
- @csrf_exempt
134
- @login_required
135
- def user_logout(request):
136
- logout(request)
137
- messages.success(request, ('You have been logged out!'))
138
- # print('logged out')
139
- return redirect('index')
140
-
141
-
142
- @csrf_exempt
143
- @login_required
144
- def upload(request):
145
- return render(request, 'upload.html')
146
-
147
-
148
- @csrf_exempt
149
- @login_required
150
- def uploader(request):
151
- global gauth
152
- if gauth.access_token_expired:
153
- # Refresh them if expired
154
- gauth.Refresh()
155
- if request.method == 'POST':
156
- folder = 'files/'
157
- file = request.FILES['file']
158
- title = request.POST['title']
159
- if title == '':
160
- title = file.name
161
- if file.name == '':
162
- return redirect('/upload/')
163
- folder_id = Userdata.objects.get(user_id=request.user).folder
164
- thread = threading.Thread(target=GoogleDriveUpload, args=(title, folder_id, file))
165
- thread.start()
166
- thread.join()
167
- return redirect('/upload/')
168
-
169
- @csrf_exempt
170
- def uploaderAI(request):
171
- global gauth
172
- if gauth.access_token_expired:
173
- # Refresh them if expired
174
- gauth.Refresh()
175
- if request.method == 'POST':
176
- try:
177
- file = request.FILES['file']
178
- title = request.POST['title']
179
- prompt = request.POST['prompt']
180
- if title == '':
181
- title = file.name
182
- folder_id = "1Hxpc5aT4xl9Nz1QUQJirJcnaT9J1QrzR"
183
- file1 = DRIVE.CreateFile({'title': title, 'description':prompt, 'parents': [{'id': folder_id}]})
184
- file1.content = file
185
- file1.Upload()
186
- return HttpResponse(json.dumps({'status': 'success'}), content_type='application/json')
187
- except Exception as e:
188
- return HttpResponse(json.dumps({'status': 'error','error':str(e)}), content_type='application/json')
189
-
190
-
191
- @csrf_exempt
192
- @login_required
193
- def list(request):
194
- global gauth
195
- if gauth.access_token_expired:
196
- # Refresh them if expired
197
- gauth.Refresh()
198
- files = []
199
- folders = []
200
- folder_id = Userdata.objects.get(user_id=request.user).folder
201
- list_files = DRIVE.ListFile({'q': "'%s' in parents and trashed=false" % folder_id}).GetList()
202
- for file in list_files:
203
- if file['title'] != 'Deleted' and file['title'] != 'DeletedFile' and file['mimeType'] != 'application/vnd.google-apps.folder':
204
- files.append([file['title'], file['embedLink'], file['id'], file["iconLink"].replace("/16/", "/32/"), file["webContentLink"]])
205
- elif file['mimeType'] == 'application/vnd.google-apps.folder':
206
- folders.append([file['title'], "/list/"+file['id'][::-1]])
207
- else:
208
- pass
209
- context = {'files': files, 'folders': folders, 'back': False}
210
- return render(request, 'list.html', context=context)
211
-
212
-
213
- @csrf_exempt
214
- @login_required
215
- def folder_list(request, id):
216
- global gauth
217
- if gauth.access_token_expired:
218
- # Refresh them if expired
219
- gauth.Refresh()
220
- files = []
221
- folders = []
222
- folder_id = id[::-1] # Userdata.objects.get(user_id=request.user).folder
223
- list_files = DRIVE.ListFile({'q': "'%s' in parents and trashed=false" % folder_id}).GetList()
224
- for file in list_files:
225
- if file['title'] != 'Deleted' and file['mimeType'] != 'application/vnd.google-apps.folder':
226
- files.append([file['title'], file['embedLink'], file['id'], file["iconLink"].replace("/16/", "/32/"), file["webContentLink"]])
227
- elif file['mimeType'] == 'application/vnd.google-apps.folder':
228
- folders.append([file['title'], "/list/"+file['id'][::-1]])
229
- else:
230
- pass
231
- context = {'files': files, 'folders': folders, 'back': True}
232
- return render(request, 'list.html', context=context)
233
-
234
-
235
- @csrf_exempt
236
- @login_required
237
- def deleteFile(request):
238
- global gauth
239
- if gauth.access_token_expired:
240
- # Refresh them if expired
241
- gauth.Refresh()
242
- if request.method == 'POST':
243
- file_id = json.loads(request.body)['file_id']
244
- file = DRIVE.CreateFile({'id': file_id})
245
- file.Trash()
246
- return HttpResponse(json.dumps({'status': 'success'}), content_type='application/json')
247
-
248
-
249
- @csrf_exempt
250
- @login_required
251
- def renameFile(request):
252
- global gauth
253
- if gauth.access_token_expired:
254
- # Refresh them if expired
255
- gauth.Refresh()
256
- if request.method == 'POST':
257
- data = json.loads(request.body)
258
- file_id = data['file_id']
259
- new_name = data['new_name']
260
- file = DRIVE.CreateFile({'id': file_id})
261
- file.FetchMetadata(fields="title")
262
- file['title'] = new_name
263
- file.Upload()
264
- return HttpResponse(json.dumps({'status': 'success'}), content_type='application/json')
265
-
266
-
267
- def torrentDownloader(link):
268
- import libtorrent as lt
269
- ses = lt.session()
270
- ses.listen_on(6881, 6891)
271
- params = {
272
- 'save_path': '/tmp/',
273
- 'storage_mode': lt.storage_mode_t(2)
274
- }
275
- handle = lt.add_magnet_uri(ses, link, params)
276
- ses.start_dht()
277
- while (not handle.has_metadata()):
278
- time.sleep(1)
279
- while (handle.status().state != lt.torrent_status.seeding):
280
- s = handle.status()
281
- state_str = ['queued', 'checking', 'downloading metadata', 'downloading', 'finished', 'seeding', 'allocating']
282
- print('%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s ' % (s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, s.num_peers, state_str[s.state]))
283
- time.sleep(5)
284
- with open('/tmp/'+handle.file_name, 'rb') as f:
285
- file = f.read()
286
- file1 = DRIVE.CreateFile({'title': handle.file_name, 'parents': [{'id': '1l6oqVFu-Ys025p7PKjIY0Nwgdr08MwlB'}]})
287
- file1.content = file
288
- file1.Upload()
289
-
290
- print('Uploaded torrent file to drive from link: ', torrent_file.file_name)
291
-
292
-
293
- @csrf_exempt
294
- def movieDownloader(request):
295
- if request.method == 'POST':
296
- data = json.loads(request.body)
297
- movie = data['movie']
298
- tmdbId = data['tmdbId']
299
- torrentLink = data['torrentLink']
300
- t1 = threading.Thread(target=torrentDownloader, args=(torrentLink,))
301
- t1.start()
302
- return HttpResponse(json.dumps({'status': 'success'}), content_type='application/json')
303
-
304
-
305
- def ipGetter(request):
306
- ip = request.GET.get('ip', '')
307
- ipIn = ip_address.objects.filter(ip=ip).first()
308
- if ipIn is None:
309
- new_entry = ip_address(ip=ip)
310
- new_entry.save()
311
- return HttpResponse(json.dumps({'status': 'success'}), content_type='application/json')
312
-
313
-
314
- @login_required
315
- def godMode(request):
316
- if request.user.is_superuser:
317
- ips = ip_address.objects.all()
318
- ipF = ips[0].ip
319
- g = geocoder.ip(ipF)
320
- myAddress = g.latlng
321
- my_map1 = folium.Map(location=myAddress, zoom_start=12)
322
- for ip in ips:
323
- g = geocoder.ip(ip.ip)
324
- myAddress = g.latlng
325
- folium.Marker(myAddress).add_to(my_map1)
326
- my_map1.save('templates/godMode.html')
327
- return render(request, 'godMode.html')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from django.shortcuts import render, redirect, HttpResponse
2
+ from django.contrib.auth import authenticate, login, logout
3
+ from django.contrib import messages
4
+ from django.contrib.auth.decorators import login_required
5
+ from django.contrib.auth.models import User
6
+ import json
7
+ from .models import Userdata, ip_address, movies
8
+ import threading
9
+ from django.conf import settings
10
+ from django.views.decorators.csrf import csrf_exempt, csrf_protect
11
+ from django.core.mail import send_mail
12
+ import os
13
+ from pydrive.auth import GoogleAuth
14
+ from pydrive.drive import GoogleDrive
15
+ import requests
16
+ import geocoder
17
+ import folium
18
+ from oauth2client import client
19
+ import time
20
+ from urllib.parse import urlparse, parse_qs
21
+
22
+ gauth = GoogleAuth()
23
+ content = '{"access_token": "ya29.a0AXooCgtLK5HzYMtRs4R9J7FRZSGR3i5jUkeMeVhGjorlrgq_BupFi8d9upA2skYC5FofxUqo23Nivk_P_Hy8eRn0DWM3deSKoiWMhA3lsy05JVakD0vd2fPRaFOXfRV20jAEGt6ql9yy_0up3Y9z8u9yXZ28IUxRRZAHaCgYKASQSARISFQHGX2MipVyGD4fFFZJWXGvyd-sJnQ0171", "client_id": "895306463817-h14aujg3ohgptue5safg2d81530qs4c3.apps.googleusercontent.com", "client_secret": "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", "refresh_token": "1//0gsu0CorccmScCgYIARAAGBASNwF-L9IrF-TDYDXR_MTQGAGGf4fY4BBBSBUipsz_7c0B6HjmRYZV3uxPVU4CAJjqWoWBm0T4pxA", "token_expiry": "2024-05-25T11:14:56Z", "token_uri": "https://oauth2.googleapis.com/token", "user_agent": null, "revoke_uri": "https://oauth2.googleapis.com/revoke", "id_token": null, "id_token_jwt": null, "token_response": {"access_token": "ya29.a0AXooCgtLK5HzYMtRs4R9J7FRZSGR3i5jUkeMeVhGjorlrgq_BupFi8d9upA2skYC5FofxUqo23Nivk_P_Hy8eRn0DWM3deSKoiWMhA3lsy05JVakD0vd2fPRaFOXfRV20jAEGt6ql9yy_0up3Y9z8u9yXZ28IUxRRZAHaCgYKASQSARISFQHGX2MipVyGD4fFFZJWXGvyd-sJnQ0171", "expires_in": 3599, "refresh_token": "1//0gsu0CorccmScCgYIARAAGBASNwF-L9IrF-TDYDXR_MTQGAGGf4fY4BBBSBUipsz_7c0B6HjmRYZV3uxPVU4CAJjqWoWBm0T4pxA", "scope": "https://www.googleapis.com/auth/drive", "token_type": "Bearer"}, "scopes": ["https://www.googleapis.com/auth/drive"], "token_info_uri": "https://oauth2.googleapis.com/tokeninfo", "invalid": false, "_class": "OAuth2Credentials", "_module": "oauth2client.client"}'
24
+ gauth.credentials = client.Credentials.new_from_json(content)
25
+ if gauth.access_token_expired:
26
+ # Refresh them if expired
27
+ gauth.Refresh()
28
+ else:
29
+ gauth.Authorize()
30
+ DRIVE = GoogleDrive(gauth)
31
+
32
+
33
+ def GoogleDriveUpload(filename, folder, file):
34
+ file1 = DRIVE.CreateFile({"title": filename, "parents": [{"id": folder}]})
35
+ file1.content = file
36
+ file1.Upload()
37
+
38
+
39
+ @csrf_exempt
40
+ def index(request):
41
+ context = {"user": request.user}
42
+ return render(request, "index.html", context=context)
43
+
44
+
45
+ @csrf_exempt
46
+ def movie(request):
47
+ all_movies = movies.objects.all()
48
+ context = {"movies": all_movies.values()}
49
+ return render(request, "movie.html", context=context)
50
+
51
+
52
+ @csrf_exempt
53
+ def movieDetail(request, id):
54
+
55
+ # Try to get movie from database
56
+ movie = movies.objects.filter(tmdbId=id).first()
57
+
58
+ # If not found or description is empty, fetch from API and save/update
59
+ if not movie or not movie.description:
60
+ url = f"https://api.themoviedb.org/3/movie/{id}?append_to_response=images,reviews,similar,recommendations,credits"
61
+ headers = {"Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI2MmY0Njg4NDE4ODI2MDNjODc1Y2EwZDMyMzE1NzkyZSIsInN1YiI6IjYyMDBlNmFmMWZkMzZmMDA2NmI5OTczNSIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.mt_t8wqYYl5b8AlDy5npgiF7sbb8ZaDh_XPauDgMt8I", "accept": "application/json"}
62
+ response = requests.get(url, headers=headers)
63
+ data = response.json()
64
+
65
+ # Prepare fields for model
66
+ movie_data = {"movie": data.get("title", ""), "poster": data.get("poster_path", ""), "backdrop": data.get("backdrop_path", ""), "trailer": "", "description": data.get("overview", ""), "Released": data.get("release_date", ""), "Genre": ", ".join([g["name"] for g in data.get("genres", [])]), "Casts": ", ".join([c["name"] for c in data.get("credits", {}).get("cast", [])[:5]]), "Duration": str(data.get("runtime", "")), "Country": ", ".join([c["name"] for c in data.get("production_countries", [])]), "Production": ", ".join([c["name"] for c in data.get("production_companies", [])]), "tmdbId": str(data.get("id", "")), "imdbId": data.get("imdb_id", ""), "uploaded": False} # You can extract trailer info from data['videos'] if needed
67
+
68
+ if movie:
69
+ # Update existing movie
70
+ for key, value in movie_data.items():
71
+ setattr(movie, key, value)
72
+ movie.save()
73
+ else:
74
+ # Create new movie
75
+ movie = movies.objects.create(**movie_data)
76
+
77
+ # Prepare data for template
78
+ data = {
79
+ "movie": movie.movie,
80
+ "poster": movie.poster,
81
+ "backdrop": movie.backdrop,
82
+ "trailer": movie.trailer,
83
+ "description": movie.description,
84
+ "Released": movie.Released,
85
+ "Genre": movie.Genre,
86
+ "Casts": movie.Casts,
87
+ "Duration": movie.Duration,
88
+ "Country": movie.Country,
89
+ "Production": movie.Production,
90
+ "tmdbId": movie.tmdbId,
91
+ "imdbId": movie.imdbId,
92
+ "torrentLink": movie.torrentLink,
93
+ "driveLink": movie.driveLink,
94
+ "uploaded": movie.uploaded,
95
+ }
96
+
97
+ # If driveLink exists, try to get watchLink
98
+ if movie.driveLink:
99
+ try:
100
+ url = "https://drive.google.com/get_video_info?docid=" + movie.driveLink + "&drive_originator_app=303"
101
+ headers = {"accept": "application/json"}
102
+ response = requests.get(url, headers=headers)
103
+ urlData = response.text
104
+ parsed_url = urlparse("https://drive.google.com/?" + urlData)
105
+ urlData = json.loads(parse_qs(parsed_url.query)["player_response"][0])
106
+ data["watchLink"] = urlData
107
+ except Exception as e:
108
+ print(e)
109
+
110
+ context = {"data": data}
111
+ return render(request, "movieDetail.html", context=context)
112
+
113
+
114
+ @csrf_exempt
115
+ def user_login(request):
116
+ if request.method == "POST":
117
+ username = request.POST["username"]
118
+ password = request.POST["password"]
119
+ user = authenticate(request, username=username, password=password)
120
+ if user is not None:
121
+ login(request, user)
122
+ messages.success(request, ("You have been logged in!"))
123
+ # print('logged in')
124
+ return redirect("index")
125
+ else:
126
+ messages.success(request, ("Error logging in - please try again."))
127
+ # print('error logging in')
128
+ return render(request, "login.html")
129
+ return render(request, "login.html")
130
+
131
+
132
+ @csrf_exempt
133
+ def sign_up(request):
134
+ if request.method == "POST":
135
+ name = request.POST["name"]
136
+ email = request.POST["email"]
137
+ password = request.POST["password"]
138
+ password2 = request.POST["password1"]
139
+ user = authenticate(request, email=email, password=password)
140
+ if user is not None and password == password2:
141
+ login(request, user)
142
+ messages.success(request, ("You have been logged in!"))
143
+ # print('logged in')
144
+ return redirect("index")
145
+ elif user is None and password == password2:
146
+ user = User.objects.create_user(username=email, email=email, password=password, first_name=name)
147
+ user.save()
148
+ messages.success(request, ("Created new user!"))
149
+ login(request, user)
150
+ folder = "1lrtX-7QPLD4vQl6Dkf65ue4aqgSTl1fZ"
151
+ new_folder = DRIVE.CreateFile({"title": name, "mimeType": "application/vnd.google-apps.folder", "parents": [{"id": folder}]})
152
+ new_folder.Upload()
153
+ new_folder.InsertPermission({"type": "user", "value": email, "role": "writer"})
154
+ dataObj = Userdata(user_id=request.user, folder=new_folder["id"])
155
+ dataObj.save()
156
+ # print('new user created')
157
+ return redirect("index")
158
+ else:
159
+ pass
160
+ return render(request, "signup.html")
161
+
162
+
163
+ @csrf_exempt
164
+ @login_required
165
+ def user_logout(request):
166
+ logout(request)
167
+ messages.success(request, ("You have been logged out!"))
168
+ # print('logged out')
169
+ return redirect("index")
170
+
171
+
172
+ @csrf_exempt
173
+ @login_required
174
+ def upload(request):
175
+ return render(request, "upload.html")
176
+
177
+
178
+ @csrf_exempt
179
+ @login_required
180
+ def uploader(request):
181
+ global gauth
182
+ if gauth.access_token_expired:
183
+ # Refresh them if expired
184
+ gauth.Refresh()
185
+ if request.method == "POST":
186
+ folder = "files/"
187
+ file = request.FILES["file"]
188
+ title = request.POST["title"]
189
+ if title == "":
190
+ title = file.name
191
+ if file.name == "":
192
+ return redirect("/upload/")
193
+ folder_id = Userdata.objects.get(user_id=request.user).folder
194
+ thread = threading.Thread(target=GoogleDriveUpload, args=(title, folder_id, file))
195
+ thread.start()
196
+ thread.join()
197
+ return redirect("/upload/")
198
+
199
+
200
+ @csrf_exempt
201
+ def uploaderAI(request):
202
+ global gauth
203
+ if gauth.access_token_expired:
204
+ # Refresh them if expired
205
+ gauth.Refresh()
206
+ if request.method == "POST":
207
+ try:
208
+ file = request.FILES["file"]
209
+ title = request.POST["title"]
210
+ prompt = request.POST["prompt"]
211
+ if title == "":
212
+ title = file.name
213
+ folder_id = "1Hxpc5aT4xl9Nz1QUQJirJcnaT9J1QrzR"
214
+ file1 = DRIVE.CreateFile({"title": title, "description": prompt, "parents": [{"id": folder_id}]})
215
+ file1.content = file
216
+ file1.Upload()
217
+ return HttpResponse(json.dumps({"status": "success"}), content_type="application/json")
218
+ except Exception as e:
219
+ return HttpResponse(json.dumps({"status": "error", "error": str(e)}), content_type="application/json")
220
+
221
+
222
+ @csrf_exempt
223
+ @login_required
224
+ def list(request):
225
+ global gauth
226
+ if gauth.access_token_expired:
227
+ # Refresh them if expired
228
+ gauth.Refresh()
229
+ files = []
230
+ folders = []
231
+ folder_id = Userdata.objects.get(user_id=request.user).folder
232
+ list_files = DRIVE.ListFile({"q": "'%s' in parents and trashed=false" % folder_id}).GetList()
233
+ for file in list_files:
234
+ if file["title"] != "Deleted" and file["title"] != "DeletedFile" and file["mimeType"] != "application/vnd.google-apps.folder":
235
+ files.append([file["title"], file["embedLink"], file["id"], file["iconLink"].replace("/16/", "/32/"), file["webContentLink"]])
236
+ elif file["mimeType"] == "application/vnd.google-apps.folder":
237
+ folders.append([file["title"], "/list/" + file["id"][::-1]])
238
+ else:
239
+ pass
240
+ context = {"files": files, "folders": folders, "back": False}
241
+ return render(request, "list.html", context=context)
242
+
243
+
244
+ @csrf_exempt
245
+ @login_required
246
+ def folder_list(request, id):
247
+ global gauth
248
+ if gauth.access_token_expired:
249
+ # Refresh them if expired
250
+ gauth.Refresh()
251
+ files = []
252
+ folders = []
253
+ folder_id = id[::-1] # Userdata.objects.get(user_id=request.user).folder
254
+ list_files = DRIVE.ListFile({"q": "'%s' in parents and trashed=false" % folder_id}).GetList()
255
+ for file in list_files:
256
+ if file["title"] != "Deleted" and file["mimeType"] != "application/vnd.google-apps.folder":
257
+ files.append([file["title"], file["embedLink"], file["id"], file["iconLink"].replace("/16/", "/32/"), file["webContentLink"]])
258
+ elif file["mimeType"] == "application/vnd.google-apps.folder":
259
+ folders.append([file["title"], "/list/" + file["id"][::-1]])
260
+ else:
261
+ pass
262
+ context = {"files": files, "folders": folders, "back": True}
263
+ return render(request, "list.html", context=context)
264
+
265
+
266
+ @csrf_exempt
267
+ @login_required
268
+ def deleteFile(request):
269
+ global gauth
270
+ if gauth.access_token_expired:
271
+ # Refresh them if expired
272
+ gauth.Refresh()
273
+ if request.method == "POST":
274
+ file_id = json.loads(request.body)["file_id"]
275
+ file = DRIVE.CreateFile({"id": file_id})
276
+ file.Trash()
277
+ return HttpResponse(json.dumps({"status": "success"}), content_type="application/json")
278
+
279
+
280
+ @csrf_exempt
281
+ @login_required
282
+ def renameFile(request):
283
+ global gauth
284
+ if gauth.access_token_expired:
285
+ # Refresh them if expired
286
+ gauth.Refresh()
287
+ if request.method == "POST":
288
+ data = json.loads(request.body)
289
+ file_id = data["file_id"]
290
+ new_name = data["new_name"]
291
+ file = DRIVE.CreateFile({"id": file_id})
292
+ file.FetchMetadata(fields="title")
293
+ file["title"] = new_name
294
+ file.Upload()
295
+ return HttpResponse(json.dumps({"status": "success"}), content_type="application/json")
296
+
297
+
298
+ def torrentDownloader(link):
299
+ import libtorrent as lt
300
+
301
+ ses = lt.session()
302
+ ses.listen_on(6881, 6891)
303
+ params = {"save_path": "/tmp/", "storage_mode": lt.storage_mode_t(2)}
304
+ handle = lt.add_magnet_uri(ses, link, params)
305
+ ses.start_dht()
306
+ while not handle.has_metadata():
307
+ time.sleep(1)
308
+ while handle.status().state != lt.torrent_status.seeding:
309
+ s = handle.status()
310
+ state_str = ["queued", "checking", "downloading metadata", "downloading", "finished", "seeding", "allocating"]
311
+ print("%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s " % (s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, s.num_peers, state_str[s.state]))
312
+ time.sleep(5)
313
+ with open("/tmp/" + handle.file_name, "rb") as f:
314
+ file = f.read()
315
+ file1 = DRIVE.CreateFile({"title": handle.file_name, "parents": [{"id": "1l6oqVFu-Ys025p7PKjIY0Nwgdr08MwlB"}]})
316
+ file1.content = file
317
+ file1.Upload()
318
+
319
+ print("Uploaded torrent file to drive from link: ", torrent_file.file_name)
320
+
321
+
322
+ @csrf_exempt
323
+ def movieDownloader(request):
324
+ if request.method == "POST":
325
+ data = json.loads(request.body)
326
+ movie = data["movie"]
327
+ tmdbId = data["tmdbId"]
328
+ torrentLink = data["torrentLink"]
329
+ t1 = threading.Thread(target=torrentDownloader, args=(torrentLink,))
330
+ t1.start()
331
+ return HttpResponse(json.dumps({"status": "success"}), content_type="application/json")
332
+
333
+
334
+ def ipGetter(request):
335
+ ip = request.GET.get("ip", "")
336
+ ipIn = ip_address.objects.filter(ip=ip).first()
337
+ if ipIn is None:
338
+ new_entry = ip_address(ip=ip)
339
+ new_entry.save()
340
+ return HttpResponse(json.dumps({"status": "success"}), content_type="application/json")
341
+
342
+
343
+ @login_required
344
+ def godMode(request):
345
+ if request.user.is_superuser:
346
+ ips = ip_address.objects.all()
347
+ ipF = ips[0].ip
348
+ g = geocoder.ip(ipF)
349
+ myAddress = g.latlng
350
+ my_map1 = folium.Map(location=myAddress, zoom_start=12)
351
+ for ip in ips:
352
+ g = geocoder.ip(ip.ip)
353
+ myAddress = g.latlng
354
+ folium.Marker(myAddress).add_to(my_map1)
355
+ my_map1.save("templates/godMode.html")
356
+ return render(request, "godMode.html")
357
+
358
+
359
+ def movieLoader(request):
360
+ mainFolderId = "1l6oqVFu-Ys025p7PKjIY0Nwgdr08MwlB"
361
+
362
+ # get all files recursively from the main folder
363
+ def get_all_files(folder_id):
364
+ files = []
365
+ list_files = DRIVE.ListFile({"q": f"'{folder_id}' in parents and trashed=false"}).GetList()
366
+ for file in list_files:
367
+ if file["mimeType"] == "application/vnd.google-apps.folder":
368
+ files.extend(get_all_files(file["id"]))
369
+ else:
370
+ files.append(file)
371
+ print(f"Found file: {file['title']} with ID: {file['id']}")
372
+ return files
373
+
374
+ all_files = get_all_files(mainFolderId)
375
+ with open("home/movies.json", "w") as f:
376
+ f.write(
377
+ json.dumps(
378
+ [
379
+ {
380
+ "movie": file["title"],
381
+ "id": file["id"],
382
+ "driveLink": file["embedLink"],
383
+ }
384
+ for file in all_files
385
+ if file["mimeType"] != "application/vnd.google-apps.folder"
386
+ ],
387
+ indent=4,
388
+ )
389
+ )
390
+ return HttpResponse(json.dumps({"status": "success"}), content_type="application/json")
391
+
392
+
393
+ def movieInputer(request):
394
+ with open("home/movies.json", "r") as f:
395
+ movies_data = json.load(f)
396
+
397
+ def search_movie_by_tmdb_id(name):
398
+ url = f"https://api.themoviedb.org/3/search/movie?query={name}&include_adult=false&language=en-US&page=1"
399
+ headers = {"accept": "application/json", "Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI2MmY0Njg4NDE4ODI2MDNjODc1Y2EwZDMyMzE1NzkyZSIsInN1YiI6IjYyMDBlNmFmMWZkMzZmMDA2NmI5OTczNSIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.mt_t8wqYYl5b8AlDy5npgiF7sbb8ZaDh_XPauDgMt8I"}
400
+ response = requests.get(url, headers=headers)
401
+ if response.status_code == 200:
402
+ return response.json()
403
+ else:
404
+ print(f"Error fetching data for TMDB ID {name}: {response.status_code}")
405
+ return None
406
+ restart = False
407
+ for movie_data in movies_data:
408
+ if "mp4" in movie_data["movie"]:
409
+
410
+ movie = movies.objects.filter(driveLink=movie_data["id"]).first()
411
+ if movie is None:
412
+ if restart:
413
+ name = movie_data["movie"].replace(".mp4", "")
414
+ queryName = name.split(".1080p")[0].strip()
415
+ queryName = queryName.replace(".", " ").replace("(", "").replace(")", "").replace("-", " ").replace("_", " ").replace("'", "").replace(":", "").replace(";", "").replace(" ", " ").replace(" ", " ")
416
+ print("searching for movie:", queryName)
417
+ search_result = []
418
+ max_attempts = 10
419
+ i = 0
420
+ while len(search_result) == 0 and i < max_attempts:
421
+ search_result = search_movie_by_tmdb_id(queryName)["results"]
422
+ if len(search_result) == 0:
423
+ queryName = " ".join(queryName.split(" ")[:-2])
424
+ i += 1
425
+ if len(search_result) > 0:
426
+ search_result = search_result[0]
427
+ # Check if movie exists, update if so, else create
428
+ movie_obj = movies.objects.filter(driveLink=movie_data["id"]).first()
429
+ movie_fields = {
430
+ "movie": search_result["title"],
431
+ "poster": search_result["poster_path"],
432
+ "backdrop": search_result["backdrop_path"],
433
+ "trailer": "",
434
+ "description": search_result["overview"],
435
+ "Released": search_result["release_date"],
436
+ "Genre": ", ".join([g["name"] for g in search_result.get("genres", [])]),
437
+ "Casts": ", ".join([c["name"] for c in search_result.get("credits", {}).get("cast", [])[:5]]),
438
+ "Duration": str(search_result.get("runtime", "")),
439
+ "Country": ", ".join([c["name"] for c in search_result.get("production_countries", [])]),
440
+ "Production": ", ".join([c["name"] for c in search_result.get("production_companies", [])]),
441
+ "tmdbId": str(search_result["id"]),
442
+ "imdbId": search_result.get("imdb_id", ""),
443
+ "torrentLink": "",
444
+ "driveLink": movie_data["id"],
445
+ "uploaded": False,
446
+ }
447
+ if movie_obj:
448
+ for key, value in movie_fields.items():
449
+ setattr(movie_obj, key, value)
450
+ movie_obj.save()
451
+ print(f"Updated movie: {movie_obj.movie} with TMDB ID: {movie_obj.tmdbId}")
452
+ else:
453
+ movies.objects.create(**movie_fields)
454
+ print(f"Added movie: {movie_fields['movie']} with TMDB ID: {movie_fields['tmdbId']}")
455
+ else:
456
+ # now just add rest of the movies
457
+ name = movie_data["movie"].replace(".mp4", "")
458
+ queryName = name.split(".1080p")[0].strip()
459
+ queryName = queryName.replace(".", " ").replace("(", "").replace(")", "").replace("-", " ").replace("_", " ").replace("'", "").replace(":", "").replace(";", "").replace(" ", " ").replace(" ", " ")
460
+ movie =movies()
461
+ movie.movie = queryName
462
+ movie.driveLink = movie_data["id"]
463
+ movie.poster = ""
464
+ movie.backdrop = ""
465
+ movie.trailer = ""
466
+ movie.description = ""
467
+ movie.Released = ""
468
+ movie.Genre = ""
469
+ movie.Casts = ""
470
+ movie.Duration = ""
471
+ movie.Country = ""
472
+ movie.Production = ""
473
+ movie.tmdbId = ""
474
+ movie.imdbId = ""
475
+ movie.torrentLink = ""
476
+ movie.uploaded = True
477
+ movie.save()
478
+ print(f"Added movie: {movie.movie} with TMDB ID: {movie.tmdbId}")
479
+
480
+
481
+
482
+ return HttpResponse(json.dumps({"status": "success"}), content_type="application/json")
templates/godMode.html CHANGED
@@ -1,78 +1,78 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
-
5
- <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
6
-
7
- <script>
8
- L_NO_TOUCH = false;
9
- L_DISABLE_3D = false;
10
- </script>
11
-
12
- <style>html, body {width: 100%;height: 100%;margin: 0;padding: 0;}</style>
13
- <style>#map {position:absolute;top:0;bottom:0;right:0;left:0;}</style>
14
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.js"></script>
15
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
16
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
17
- <script src="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js"></script>
18
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.css"/>
19
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"/>
20
- <link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"/>
21
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/all.min.css"/>
22
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css"/>
23
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/python-visualization/folium/folium/templates/leaflet.awesome.rotate.min.css"/>
24
-
25
- <meta name="viewport" content="width=device-width,
26
- initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
27
- <style>
28
- #map_f83a88f12360719b8d5108477e64fbcf {
29
- position: relative;
30
- width: 100.0%;
31
- height: 100.0%;
32
- left: 0.0%;
33
- top: 0.0%;
34
- }
35
- .leaflet-container { font-size: 1rem; }
36
- </style>
37
-
38
- </head>
39
- <body>
40
-
41
-
42
- <div class="folium-map" id="map_f83a88f12360719b8d5108477e64fbcf" ></div>
43
-
44
- </body>
45
- <script>
46
-
47
-
48
- var map_f83a88f12360719b8d5108477e64fbcf = L.map(
49
- "map_f83a88f12360719b8d5108477e64fbcf",
50
- {
51
- center: [22.2916, 70.7932],
52
- crs: L.CRS.EPSG3857,
53
- zoom: 12,
54
- zoomControl: true,
55
- preferCanvas: false,
56
- }
57
- );
58
-
59
-
60
-
61
-
62
-
63
- var tile_layer_a2e3a495395fce5ac855e71111a3d95c = L.tileLayer(
64
- "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
65
- {"attribution": "\u0026copy; \u003ca href=\"https://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors", "detectRetina": false, "maxNativeZoom": 19, "maxZoom": 19, "minZoom": 0, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false}
66
- );
67
-
68
-
69
- tile_layer_a2e3a495395fce5ac855e71111a3d95c.addTo(map_f83a88f12360719b8d5108477e64fbcf);
70
-
71
-
72
- var marker_42ec10f3bb57a07b25f279b217982f24 = L.marker(
73
- [22.2916, 70.7932],
74
- {}
75
- ).addTo(map_f83a88f12360719b8d5108477e64fbcf);
76
-
77
- </script>
78
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+
5
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
6
+
7
+ <script>
8
+ L_NO_TOUCH = false;
9
+ L_DISABLE_3D = false;
10
+ </script>
11
+
12
+ <style>html, body {width: 100%;height: 100%;margin: 0;padding: 0;}</style>
13
+ <style>#map {position:absolute;top:0;bottom:0;right:0;left:0;}</style>
14
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.js"></script>
15
+ <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
16
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
17
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js"></script>
18
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.css"/>
19
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"/>
20
+ <link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"/>
21
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/all.min.css"/>
22
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css"/>
23
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/python-visualization/folium/folium/templates/leaflet.awesome.rotate.min.css"/>
24
+
25
+ <meta name="viewport" content="width=device-width,
26
+ initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
27
+ <style>
28
+ #map_f83a88f12360719b8d5108477e64fbcf {
29
+ position: relative;
30
+ width: 100.0%;
31
+ height: 100.0%;
32
+ left: 0.0%;
33
+ top: 0.0%;
34
+ }
35
+ .leaflet-container { font-size: 1rem; }
36
+ </style>
37
+
38
+ </head>
39
+ <body>
40
+
41
+
42
+ <div class="folium-map" id="map_f83a88f12360719b8d5108477e64fbcf" ></div>
43
+
44
+ </body>
45
+ <script>
46
+
47
+
48
+ var map_f83a88f12360719b8d5108477e64fbcf = L.map(
49
+ "map_f83a88f12360719b8d5108477e64fbcf",
50
+ {
51
+ center: [22.2916, 70.7932],
52
+ crs: L.CRS.EPSG3857,
53
+ zoom: 12,
54
+ zoomControl: true,
55
+ preferCanvas: false,
56
+ }
57
+ );
58
+
59
+
60
+
61
+
62
+
63
+ var tile_layer_a2e3a495395fce5ac855e71111a3d95c = L.tileLayer(
64
+ "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
65
+ {"attribution": "\u0026copy; \u003ca href=\"https://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors", "detectRetina": false, "maxNativeZoom": 19, "maxZoom": 19, "minZoom": 0, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false}
66
+ );
67
+
68
+
69
+ tile_layer_a2e3a495395fce5ac855e71111a3d95c.addTo(map_f83a88f12360719b8d5108477e64fbcf);
70
+
71
+
72
+ var marker_42ec10f3bb57a07b25f279b217982f24 = L.marker(
73
+ [22.2916, 70.7932],
74
+ {}
75
+ ).addTo(map_f83a88f12360719b8d5108477e64fbcf);
76
+
77
+ </script>
78
  </html>
templates/movie.html CHANGED
@@ -69,16 +69,45 @@
69
  </div>
70
  <!-- buttons - end -->
71
  </header>
72
- <div class="grid-cols-6 grid gap-5 px-20">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  {% for movie in movies %}
74
- <a href="{{movie.tmdbId}}" class="h-fit w-full rounded-lg overflow-hidden shadow-xl">
75
- <img class="h-auto w-full object-cover" src="https://image.tmdb.org/t/p/w600_and_h900_bestv2/{{movie.poster}}" />
76
- <p class="px-1 mt-2 font-bold">{{movie.movie}}</p>
77
- <p class="px-1 mb-2 opacity-80">{{movie.Released}}</p>
78
- </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  {% endfor %}
80
  </div>
81
- <button class="demo-btn">Click Me</button>
82
  </div>
83
  <script>
84
  function inB(event) {
@@ -93,75 +122,25 @@
93
  ass[i].classList.add("hidden");
94
  }
95
  }
96
- </script>
97
-
98
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
99
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
100
- <!-- <script src="https://getcssscan.com/js/solid.min.js"></script>
101
- <script src="https://getcssscan.com/js/lity.min.js"></script> -->
102
- <!--!-->
103
- <!-- <script src="https://getcssscan.com/js/jquery.countdown.min.js"></script> -->
104
- <script>
105
- const minWidthToRunDemo = 1024;
106
-
107
- function canRunDemo() {
108
- return window.innerWidth >= minWidthToRunDemo;
109
- }
110
-
111
- function loadDemoScript() {
112
- const demo_script = document.querySelector("#cssscan-demo-script");
113
- const demo_loading_warning = document.querySelector(".loading-demo");
114
-
115
- if (!demo_script) {
116
- const script = document.createElement("script");
117
- script.setAttribute("src", "demo-build/main.js");
118
- script.id = "cssscan-demo-script";
119
- document.body.appendChild(script);
120
-
121
- script.onload = () => {
122
- script.dataset.loaded = true;
123
- if (demo_loading_warning && demo_loading_warning.style.display !== "") {
124
- window.cssScanReady();
125
- try {
126
- demo_loading_warning.remove();
127
- } catch (e) {}
128
- }
129
- };
130
- }
131
- }
132
-
133
- if (canRunDemo()) {
134
- loadDemoScript();
135
- }
136
-
137
- window.onresize = function (e) {
138
- const demo_script = document.querySelector("#cssscan-demo-script");
139
 
140
- if (canRunDemo() && (!demo_script || (demo_script && !demo_script.dataset.loaded))) {
141
- loadDemoScript();
142
- }
143
- };
144
-
145
- const demo_btn = document.getElementsByClassName("demo-btn");
146
-
147
- for (var i = 0; i < demo_btn.length; i++) {
148
- demo_btn[i].addEventListener("click", function (e) {
149
- const demo_script = document.querySelector("#cssscan-demo-script");
150
- const demo_loading_warning = document.querySelector(".loading-demo");
151
-
152
- if (demo_script && !demo_script.dataset.loaded) {
153
- if (demo_loading_warning && demo_loading_warning.style.display === "") {
154
- demo_loading_warning.style.display = "inline-block";
155
- }
156
- } else if (demo_script && demo_script.dataset.loaded) {
157
- try {
158
- demo_loading_warning.remove();
159
- } catch (e) {}
160
  }
161
  });
162
  }
 
 
 
 
 
163
  </script>
164
- <script src="{% static 'demo.js' %}"></script>
165
- <!-- <script src="https://getcssscan.com/demo-build/main.js" id="cssscan-demo-script" data-loaded="true"></script> -->
166
  </body>
167
  </html>
 
69
  </div>
70
  <!-- buttons - end -->
71
  </header>
72
+
73
+ <!-- Add search bar here, above movies grid -->
74
+ <div class="flex justify-start px-20 mb-6">
75
+ <div id="searchBarContainer" class="flex w-full max-w-xl">
76
+ <input
77
+ id="movieSearchInput"
78
+ type="text"
79
+ placeholder="Search movies..."
80
+ class="w-full px-4 py-2 border border-gray-300 rounded-l-lg focus:outline-none focus:ring-2 focus:ring-indigo-400"
81
+ oninput="filterMovies()"
82
+ />
83
+ <button type="button" onclick="clearSearch()" class="px-4 py-2 bg-indigo-500 text-white rounded-r-lg hover:bg-indigo-600 transition">Clear</button>
84
+ </div>
85
+ </div>
86
+ <div class="grid-cols-6 grid gap-5 px-20" id="movieGrid">
87
  {% for movie in movies %}
88
+ <div onclick="location.href='/movie/{{movie.tmdbId}}'" class="movie-card bg-white rounded-xl shadow-lg overflow-hidden flex flex-col hover:scale-105 transition-transform duration-300 group" data-title="{{movie.movie|lower}}">
89
+ <div class="relative">
90
+ <img class="w-full h-64 object-cover group-hover:opacity-80 transition" src="https://image.tmdb.org/t/p/w600_and_h900_bestv2/{{movie.poster}}" alt="{{movie.movie}} poster" />
91
+ <a href="{{movie.trailer}}" target="_blank" class="absolute bottom-2 right-2 bg-indigo-600 text-white px-3 py-1 rounded-full text-xs font-semibold shadow hover:bg-indigo-700 transition">Trailer</a>
92
+ </div>
93
+ <div class="p-4 flex flex-col flex-1">
94
+ <h2 class="text-lg font-bold mb-1 truncate" title="{{movie.movie}}">{{movie.movie}}</h2>
95
+ <p class="text-sm text-gray-500 mb-2">{{movie.Released}} &bull; {{movie.Duration}}</p>
96
+ <p class="text-sm text-gray-700 mb-3 line-clamp-3">{{movie.description}}</p>
97
+ <div class="flex flex-wrap gap-2 mt-auto">
98
+ {% if movie.torrentLink %}
99
+ <a href="{{movie.torrentLink}}" target="_blank" class="bg-green-500 text-white text-xs px-3 py-1 rounded hover:bg-green-600 transition">Torrent</a>
100
+ {% endif %}
101
+ {% if movie.driveLink %}
102
+ <a href="{{movie.driveLink}}" target="_blank" class="bg-blue-500 text-white text-xs px-3 py-1 rounded hover:bg-blue-600 transition">Drive</a>
103
+ {% endif %}
104
+ <a href="https://www.imdb.com/title/{{movie.imdbId}}" target="_blank" class="bg-yellow-500 text-white text-xs px-3 py-1 rounded hover:bg-yellow-600 transition">IMDb</a>
105
+ <a href="{{movie.tmdbId}}" class="bg-indigo-500 text-white text-xs px-3 py-1 rounded hover:bg-indigo-600 transition">Details</a>
106
+ </div>
107
+ </div>
108
+ </div>
109
  {% endfor %}
110
  </div>
 
111
  </div>
112
  <script>
113
  function inB(event) {
 
122
  ass[i].classList.add("hidden");
123
  }
124
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
+ // Filter movies client-side
127
+ function filterMovies() {
128
+ const query = document.getElementById('movieSearchInput').value.trim().toLowerCase();
129
+ const cards = document.querySelectorAll('.movie-card');
130
+ cards.forEach(card => {
131
+ const title = card.getAttribute('data-title');
132
+ if (title.includes(query)) {
133
+ card.style.display = '';
134
+ } else {
135
+ card.style.display = 'none';
 
 
 
 
 
 
 
 
 
 
136
  }
137
  });
138
  }
139
+
140
+ function clearSearch() {
141
+ document.getElementById('movieSearchInput').value = '';
142
+ filterMovies();
143
+ }
144
  </script>
 
 
145
  </body>
146
  </html>
templates/movieDetail.html CHANGED
@@ -1,156 +1,199 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <title>{{data.title}}</title>
6
- <script src="https://cdn.tailwindcss.com"></script>
7
- </head>
8
- <body>
9
- <div class="bg-white relative overflow-x-hidden h-full min-h-screen">
10
- <div id="previewContainer" class="bg-[#313131] origin-center absolute flex flex-col scale-0 top-0 left-0 h-full w-full transition-all duration-500 z-50">
11
- <svg onclick="preview('{{ file.2 }}')" width="32" height="32" class="top-5 right-20 fixed top-0 bg-red-500 p-1 hover:scale-110 transition-all cursor-pointer z-50 rounded-full" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
12
- <path fill-rule="evenodd" d="M11.293 3.293a1 1 0 1 1 1.414 1.414L9.414 8l3.293 3.293a1 1 0 0 1-1.414 1.414L8 9.414l-3.293 3.293a1 1 0 0 1-1.414-1.414L6.586 8 3.293 4.707a1 1 0 0 1 1.414-1.414L8 6.586z" />
13
- </svg>
14
-
15
- <iframe id="previewIframe" src="" frameborder="0" seamless="" draggable="false" loading="lazy" decoding="async" data-nimg="1" class="fixed top-0 h-[100vh] w-full z-10 rounded-sm object-cover object-center" style="color: transparent"></iframe>
16
- </div>
17
- <header class="h-20 flex m-4 justify-between items-center mb-4">
18
- <!-- logo - start -->
19
- <a href="/" class="my-5 inline-flex items-center text-black-800 text-2xl md:text-3xl font-bold gap-2.5" aria-label="logo">
20
- <svg class="w-[10%] text-indigo-500" id="outputsvg" xmlns="http://www.w3.org/2000/svg" style="transform: none; transform-origin: 50% 50%; cursor: move; transition: none 0s ease 0s" viewBox="0 0 3500 3500">
21
- <g id="l5TLm6F9JGem8YOQ8A41YML" fill="rgb(100,103,241)" style="transform: none">
22
- <g><path id="pulsHdoRs" d="M1455 3470 c-164 -30 -323 -83 -480 -160 -487 -242 -829 -689 -935 -1226 -28 -139 -37 -389 -21 -534 64 -550 390 -1040 879 -1319 170 -98 440 -186 642 -211 203 -24 460 -7 658 45 609 160 1093 651 1246 1263 120 479 34 978 -238 1387 -258 387 -641 646 -1101 745 -149 33 -495 38 -650 10z m488 -574 c37 -7 70 -15 72 -18 3 -3 -39 -24 -92 -48 -214 -94 -369 -196 -520 -343 -336 -327 -433 -761 -242 -1084 19 -31 67 -89 107 -130 40 -40 70 -73 67 -73 -15 0 -143 54 -225 95 -221 111 -505 336 -517 410 -9 55 17 270 43 362 121 418 441 719 869 818 117 28 326 33 438 11z m360 -132 c271 -152 315 -279 149 -436 -70 -67 -94 -78 -165 -78 -46 0 -61 6 -127 51 -90 62 -156 92 -258 121 -65 17 -95 20 -187 15 -153 -7 -269 -48 -381 -133 -27 -21 -44 -31 -38 -23 110 147 205 237 364 343 100 67 296 166 395 199 l70 24 55 -23 c30 -12 85 -39 123 -60z m-1463 -1370 c262 -187 520 -287 807 -314 125 -12 210 -3 313 31 81 26 86 29 188 96 128 86 196 84 296 -8 59 -54 106 -135 106 -183 -1 -41 -30 -104 -66 -139 -47 -47 -187 -136 -271 -172 -299 -129 -612 -133 -916 -10 -250 102 -488 336 -599 590 -42 96 -74 194 -83 254 l-7 44 73 -64 c41 -36 112 -92 159 -125z"></path></g>
23
- </g>
24
- </svg>
25
- Cloud Storage
26
- </a>
27
- <!-- logo - end -->
28
-
29
- <!-- nav - start -->
30
- <nav class="hidden lg:flex gap-12">
31
- <a href="/" class="text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Home</a>
32
- <a href="/list" class="text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">List</a>
33
- <a href="/upload" class="text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Upload</a>
34
- <a href="/movie" class="text-indigo-500 text-lg font-semibold">Movie</a>
35
- <a href="/logout" class="text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Logout</a>
36
- </nav>
37
- <!-- nav - end -->
38
-
39
- <!-- buttons - start -->
40
- <div id="nav" onmouseout="outB()" onmouseover="inB()" class="overflow-visible z-10 mt-[150px] grid grid-cols-1 grid-rows-5">
41
- <button type="button" class="shadow-xl inline-flex items-center lg:hidden bg-gray-200 hover:bg-gray-300 focus-visible:ring ring-indigo-300 text-gray-500 active:text-gray-700 text-sm md:text-base font-semibold rounded-lg gap-2 px-2.5 py-2">
42
- <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 20 20" fill="currentColor">
43
- <path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h6a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd" />
44
- </svg>
45
- Menu
46
- </button>
47
- <a href="../" class="mt-2 hidden bg-white rounded-t-lg px-2 text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Home</a>
48
- <a href="../list" class="shadow-xl hidden bg-white px-2 text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">List</a>
49
- <a href="../upload" class="shadow-xl hidden bg-white px-2 text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Upload</a>
50
- <a href="../movie" class="shadow-xl hidden bg-white px-2 text-indigo-500 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Movie</a>
51
- <a href="../logout" class="shadow-xl hidden bg-white px-2 text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100 rounded-b-lg">Logout</a>
52
- </div>
53
- <!-- buttons - end -->
54
- </header>
55
- <section class="relative">
56
- <div class="absolute h-full w-full bg-cover bg-[top_center] bg-no-repeat">
57
- <img src="https://image.tmdb.org/t/p/w1280{{data.backdrop_path}}" class="w-full opacity-50 object-cover h-full blur-2xl scale-110 translate-y-16" />
58
- </div>
59
-
60
- <div class="mx-auto w-[80%] h-full py-10">
61
- <div class="flex flex-col gap-10">
62
- <div class="z-[2] flex flex-col items-start gap-10 lg:flex-row">
63
- <div class="flex w-full flex-col items-center justify-center rounded-xl lg:block lg:w-auto">
64
- <div class="group relative flex w-full items-center justify-center hover:cursor-pointer">
65
- <a target="_blank" class="absolute inset-x-0 mx-auto flex h-full w-full items-center justify-center opacity-0 transition-opacity group-hover:opacity-100 md:hidden" href="https://youtube.com/watch?v=Y0ZsLudtfjI">
66
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-play h-20 w-20 text-white">
67
- <circle cx="12" cy="12" r="10"></circle>
68
- <polygon points="10 8 16 12 10 16 10 8"></polygon>
69
- </svg>
70
- </a>
71
- <button type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="radix-:Rid7rrqja:" data-state="closed" class="absolute inset-x-0 mx-auto hidden h-full w-full items-center justify-center opacity-0 transition-opacity group-hover:opacity-100 md:flex">
72
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-play h-20 w-20 text-white">
73
- <circle cx="12" cy="12" r="10"></circle>
74
- <polygon points="10 8 16 12 10 16 10 8"></polygon>
75
- </svg>
76
- </button>
77
- <img loading="lazy" width="300" height="400" decoding="async" data-nimg="1" class="rounded-xl border-[3px] border-white" style="color: transparent" src="https://image.tmdb.org/t/p/w1280{{data.poster_path}}" />
78
- </div>
79
- </div>
80
- <div class="flex-1 space-y-5">
81
- <div class="space-y-3">
82
- <h1 class="text-3xl font-bold tracking-wide">{{data.title}}</h1>
83
- <div class="flex flex-col items-start gap-2 md:flex-row md:items-center">
84
- <p>{{data.release_date }}</p>
85
- <span class="hidden md:inline-block">•</span>
86
- <div class="space-x-2">
87
- {% for genre in data.genres %}
88
- <span class="underline underline-offset-4">{{genre.name}}</span>
89
- {% endfor %}
90
- </div>
91
- <span class="hidden md:inline-block">•</span>
92
- <p>{{data.runtime}}<!-- -->min</p>
93
- </div>
94
- </div>
95
- <div class="flex flex-col gap-2">
96
- <div class="flex items-center gap-2">
97
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#FF9900" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-star text-[#FF9900]"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon></svg>
98
- <p class="text-lg capitalize">{{data.vote_average}} / 10</p>
99
- </div>
100
- <div class="flex items-center gap-2">
101
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-thumbs-up">
102
- <path d="M7 10v12"></path>
103
- <path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z"></path>
104
- </svg>
105
- <p class="text-lg capitalize">{{data.vote_count}}</p>
106
- </div>
107
- </div>
108
- <div class="flex w-full flex-col gap-3">
109
- <h1 class="text-xl font-semibold">Plot Summary</h1>
110
- <p class="line-clamp-4">{{data.overview}}</p>
111
- </div>
112
- <div class="space-y-5">
113
- <h1 class="text-xl font-semibold">Top Casts</h1>
114
- <div class="flex overflow-x-scroll w-[50rem] flex-row items-center gap-10">
115
- {% for cast in data.credits.cast %}
116
- <div class="flex items-center gap-2 w-fit mr-5">
117
- <img alt="{{cast.name}}" loading="lazy" width="50" height="50" decoding="async" data-nimg="1" class="rounded-full border-2 border-white aspect-square object-cover" src="https://media.themoviedb.org/t/p/w138_and_h175_face/{{cast.profile_path}}" />
118
- <div class="flex flex-col w-full">
119
- <p class="font-semibold whitespace-nowrap">{{cast.name}}</p>
120
- <p class="text-sm text-foreground/50 whitespace-nowrap">{{cast.character}}</p>
121
- </div>
122
- </div>
123
- {% endfor %}
124
- </div>
125
- </div>
126
- </div>
127
- </div>
128
- </div>
129
- </div>
130
- <video controls="controls" id="moviePlayer" class="absolute inset-0 z-50 w-full h-full object-cover">
131
- {% for link in data.watchLink.streamingData.adaptiveFormats %}
132
- <source src="{{link.url}}" type="video/mp4" />
133
- {% endfor %}
134
- </video>
135
- </section>
136
- </div>
137
- <script>
138
- function inB(event) {
139
- ass = document.getElementById("nav").getElementsByTagName("a");
140
- for (let i = 0; i < ass.length; i++) {
141
- ass[i].classList.remove("hidden");
142
- }
143
- }
144
- function outB(event) {
145
- ass = document.getElementById("nav").getElementsByTagName("a");
146
- for (let i = 0; i < ass.length; i++) {
147
- ass[i].classList.add("hidden");
148
- }
149
- }
150
- function openMovie(id) {
151
- let videoLink = "https://drive.google.com/uc?export=download&id=" + id;
152
- document.getElementById("moviePlayer").src = videoLink;
153
- }
154
- </script>
155
- </body>
156
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <title>{{data.title}}</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ </head>
9
+
10
+ <body>
11
+ <div class="bg-white relative overflow-x-hidden h-full min-h-screen">
12
+ <div id="previewContainer"
13
+ class="bg-white origin-center absolute flex flex-col scale-0 top-0 left-0 h-full w-full transition-all duration-500 z-50">
14
+ <svg onclick="preview('{{ file.2 }}')" width="32" height="32"
15
+ class="top-5 right-20 fixed top-0 bg-red-500 p-1 hover:scale-110 transition-all cursor-pointer z-50 rounded-full"
16
+ viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
17
+ <path fill-rule="evenodd"
18
+ d="M11.293 3.293a1 1 0 1 1 1.414 1.414L9.414 8l3.293 3.293a1 1 0 0 1-1.414 1.414L8 9.414l-3.293 3.293a1 1 0 0 1-1.414-1.414L6.586 8 3.293 4.707a1 1 0 0 1 1.414-1.414L8 6.586z" />
19
+ </svg>
20
+
21
+ <iframe id="previewIframe" src="" frameborder="0" seamless="" draggable="false" loading="lazy"
22
+ decoding="async" data-nimg="1"
23
+ class="fixed top-0 h-[100vh] w-full z-10 rounded-sm object-cover object-center"
24
+ style="color: transparent"></iframe>
25
+ </div>
26
+ <header class="h-20 flex m-4 justify-between items-center mb-4">
27
+ <!-- logo - start -->
28
+ <a href="/" class="my-5 inline-flex items-center text-black-800 text-2xl md:text-3xl font-bold gap-2.5"
29
+ aria-label="logo">
30
+ <svg class="w-[10%] text-indigo-500" id="outputsvg" xmlns="http://www.w3.org/2000/svg"
31
+ style="transform: none; transform-origin: 50% 50%; cursor: move; transition: none 0s ease 0s"
32
+ viewBox="0 0 3500 3500">
33
+ <g id="l5TLm6F9JGem8YOQ8A41YML" fill="rgb(100,103,241)" style="transform: none">
34
+ <g>
35
+ <path id="pulsHdoRs"
36
+ d="M1455 3470 c-164 -30 -323 -83 -480 -160 -487 -242 -829 -689 -935 -1226 -28 -139 -37 -389 -21 -534 64 -550 390 -1040 879 -1319 170 -98 440 -186 642 -211 203 -24 460 -7 658 45 609 160 1093 651 1246 1263 120 479 34 978 -238 1387 -258 387 -641 646 -1101 745 -149 33 -495 38 -650 10z m488 -574 c37 -7 70 -15 72 -18 3 -3 -39 -24 -92 -48 -214 -94 -369 -196 -520 -343 -336 -327 -433 -761 -242 -1084 19 -31 67 -89 107 -130 40 -40 70 -73 67 -73 -15 0 -143 54 -225 95 -221 111 -505 336 -517 410 -9 55 17 270 43 362 121 418 441 719 869 818 117 28 326 33 438 11z m360 -132 c271 -152 315 -279 149 -436 -70 -67 -94 -78 -165 -78 -46 0 -61 6 -127 51 -90 62 -156 92 -258 121 -65 17 -95 20 -187 15 -153 -7 -269 -48 -381 -133 -27 -21 -44 -31 -38 -23 110 147 205 237 364 343 100 67 296 166 395 199 l70 24 55 -23 c30 -12 85 -39 123 -60z m-1463 -1370 c262 -187 520 -287 807 -314 125 -12 210 -3 313 31 81 26 86 29 188 96 128 86 196 84 296 -8 59 -54 106 -135 106 -183 -1 -41 -30 -104 -66 -139 -47 -47 -187 -136 -271 -172 -299 -129 -612 -133 -916 -10 -250 102 -488 336 -599 590 -42 96 -74 194 -83 254 l-7 44 73 -64 c41 -36 112 -92 159 -125z">
37
+ </path>
38
+ </g>
39
+ </g>
40
+ </svg>
41
+ Cloud Storage
42
+ </a>
43
+ <!-- logo - end -->
44
+
45
+ <!-- nav - start -->
46
+ <nav class="hidden lg:flex gap-12">
47
+ <a href="/"
48
+ class="text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Home</a>
49
+ <a href="/list"
50
+ class="text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">List</a>
51
+ <a href="/upload"
52
+ class="text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Upload</a>
53
+ <a href="/movie" class="text-indigo-500 text-lg font-semibold">Movie</a>
54
+ <a href="/logout"
55
+ class="text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Logout</a>
56
+ </nav>
57
+ <!-- nav - end -->
58
+
59
+ <!-- buttons - start -->
60
+ <div id="nav" onmouseout="outB()" onmouseover="inB()"
61
+ class="overflow-visible z-10 mt-[150px] grid grid-cols-1 grid-rows-5">
62
+ <button type="button"
63
+ class="shadow-xl inline-flex items-center lg:hidden bg-gray-200 hover:bg-gray-300 focus-visible:ring ring-indigo-300 text-gray-500 active:text-gray-700 text-sm md:text-base font-semibold rounded-lg gap-2 px-2.5 py-2">
64
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 20 20" fill="currentColor">
65
+ <path fill-rule="evenodd"
66
+ d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h6a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
67
+ clip-rule="evenodd" />
68
+ </svg>
69
+ Menu
70
+ </button>
71
+ <a href="../"
72
+ class="mt-2 hidden bg-white rounded-t-lg px-2 text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Home</a>
73
+ <a href="../list"
74
+ class="shadow-xl hidden bg-white px-2 text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">List</a>
75
+ <a href="../upload"
76
+ class="shadow-xl hidden bg-white px-2 text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Upload</a>
77
+ <a href="../movie"
78
+ class="shadow-xl hidden bg-white px-2 text-indigo-500 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100">Movie</a>
79
+ <a href="../logout"
80
+ class="shadow-xl hidden bg-white px-2 text-gray-600 hover:text-indigo-500 active:text-indigo-700 text-lg font-semibold transition duration-100 rounded-b-lg">Logout</a>
81
+ </div>
82
+ <!-- buttons - end -->
83
+ </header>
84
+ <section class="relative bg-gradient-to-b from-[#f8fafc] to-[#e0e7ef] min-h-[90vh] py-12 px-0 md:px-0">
85
+ <div class="absolute top-0 inset-0 z-0">
86
+ <img src="https://media.themoviedb.org/t/p/w1920_and_h800_multi_faces/{{data.backdrop}}" alt="Backdrop"
87
+ class="w-full h-full object-cover opacity-20 scale-100" />
88
+ <div class="absolute inset-0 bg-gradient-to-b from-white/60 to-white/75 backdrop-blur-md"></div>
89
+ </div>
90
+ <div
91
+ class="relative z-10 max-w-6xl mx-auto flex flex-col md:flex-row gap-10 items-start bg-white/80 rounded-2xl shadow-2xl p-8 backdrop-blur-md">
92
+ <!-- Poster & Trailer -->
93
+ <div class="flex flex-col items-center gap-6 w-full md:w-1/3">
94
+ <div class="relative group w-full">
95
+ <img src="https://media.themoviedb.org/t/p/w300_and_h450_bestv2/{{data.poster}}" alt="Poster"
96
+ class="rounded-xl border-4 border-gray-200 shadow-lg w-full max-w-xs mx-auto object-cover" />
97
+ {% if data.trailer %}
98
+ <a href="{{ data.trailer }}" target="_blank"
99
+ class="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity bg-white/70 rounded-xl">
100
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-20 w-20 text-indigo-600 drop-shadow-lg"
101
+ fill="none" viewBox="0 0 24 24" stroke="currentColor">
102
+ <circle cx="12" cy="12" r="10" fill="rgba(99,102,241,0.15)" />
103
+ <polygon points="10 8 16 12 10 16 10 8" fill="#6366f1" />
104
+ </svg>
105
+ </a>
106
+ {% endif %}
107
+ </div>
108
+ {% if data.torrentLink %}
109
+ <a href="{{ data.torrentLink }}" target="_blank"
110
+ class="w-full text-center bg-indigo-500 hover:bg-indigo-600 text-white font-semibold py-2 rounded-lg shadow transition">Download
111
+ Torrent</a>
112
+ {% endif %}
113
+ {% if data.driveLink %}
114
+ <a href="{{ data.driveLink }}" target="_blank"
115
+ class="w-full text-center bg-green-500 hover:bg-green-600 text-white font-semibold py-2 rounded-lg shadow transition">Watch
116
+ on Drive</a>
117
+ {% endif %}
118
+ </div>
119
+ <!-- Movie Details -->
120
+ <div class="flex-1 flex flex-col gap-6">
121
+ <div>
122
+ <h1 class="text-4xl font-extrabold text-gray-900 mb-2 tracking-tight">{{ data.movie }}</h1>
123
+ <div
124
+ class="flex flex-wrap whitespace-wrap items-center gap-3 text-gray-700 text-base font-medium">
125
+ {% if data.Released %}
126
+ <span class="bg-indigo-100 text-indigo-700 px-3 py-1 rounded-full">{{data.Released}}</span>
127
+ <span>•</span>
128
+ {% endif %}
129
+ {% if data.Duration %}
130
+ <span class="bg-gray-200 text-gray-700 px-3 py-1 rounded-full">{{ data.Duration }}
131
+ min</span>
132
+ <span>•</span>
133
+ {% endif %}
134
+ {% if data.Country %}
135
+ <span class="bg-gray-200 text-gray-700 px-3 py-1 rounded-full">{{ data.Country}}</span>
136
+ <span>•</span>
137
+ {% endif %}
138
+ {% if data.Production %}
139
+ <span class="text-gray-700">{{ data.Production}}</span>
140
+ {% endif %}
141
+ </div>
142
+ <div class="flex flex-wrap gap-2 mt-3">
143
+ <span class="bg-indigo-200 text-indigo-800 px-2 py-1 rounded text-xs font-semibold">
144
+ {{ data.Genre }}
145
+ </span>
146
+ </div>
147
+ </div>
148
+ <div>
149
+ <h2 class="text-xl font-semibold text-gray-900 mb-1">Plot Summary</h2>
150
+ <p class="text-gray-800 text-base leading-relaxed">{{ data.description }}
151
+ </p>
152
+ </div>
153
+ <div class="flex flex-wrap gap-4 mt-4">
154
+ {% if data.imdbId %}
155
+ <a href="https://www.imdb.com/title/{{ data.imdbId }}" target="_blank"
156
+ class="flex items-center gap-2 bg-yellow-400 hover:bg-yellow-500 text-black font-bold px-4 py-2 rounded transition">
157
+
158
+ IMDb
159
+ </a>
160
+ {% endif %}
161
+ {% if data.tmdbId %}
162
+ <a href="https://www.themoviedb.org/movie/{{ data.tmdbId }}" target="_blank"
163
+ class="flex items-center gap-2 bg-cyan-400 hover:bg-cyan-500 text-white font-bold px-4 py-2 rounded transition">
164
+
165
+ TMDB
166
+ </a>
167
+ {% endif %}
168
+ </div>
169
+ </div>
170
+ </div>
171
+ <!-- Optional: Video Player -->
172
+ {% if data.driveLink %}
173
+ <div class="relative z-20 max-w-6xl mx-auto mt-12 rounded-xl overflow-hidden shadow-2xl">
174
+ <iframe src="https://drive.google.com/file/d/{{ data.driveLink }}/preview" class="w-full h-[400px] bg-gray-100" allowfullscreen></iframe>
175
+ </div>
176
+ {% endif %}
177
+ </section>
178
+ </div>
179
+ <script>
180
+ function inB(event) {
181
+ ass = document.getElementById("nav").getElementsByTagName("a");
182
+ for (let i = 0; i < ass.length; i++) {
183
+ ass[i].classList.remove("hidden");
184
+ }
185
+ }
186
+ function outB(event) {
187
+ ass = document.getElementById("nav").getElementsByTagName("a");
188
+ for (let i = 0; i < ass.length; i++) {
189
+ ass[i].classList.add("hidden");
190
+ }
191
+ }
192
+ function openMovie(id) {
193
+ let videoLink = "https://drive.google.com/uc?export=download&id=" + id;
194
+ document.getElementById("moviePlayer").src = videoLink;
195
+ }
196
+ </script>
197
+ </body>
198
+
199
+ </html>