Compare commits
26 Commits
dev-monito
...
v0.19.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 497a3a74cd | |||
| 101460cd47 | |||
| 591c9cdd2a | |||
| 2dc53c5270 | |||
| 5938d33c89 | |||
| d95ab85415 | |||
| cc39e46bfd | |||
| ba092ab3c2 | |||
| 774d6f4999 | |||
| 0b56ee937d | |||
| 7b3d57b94a | |||
| be7b610111 | |||
| 3e93a7c9c1 | |||
| bc78b83f8d | |||
| c5bcaeb1d4 | |||
| e39182ba91 | |||
| 965b747594 | |||
| 937e3c6270 | |||
| 2bb2845ead | |||
| fca189648b | |||
| 2121466322 | |||
| 1e130c3490 | |||
| 4b97faeadb | |||
| 3701e31ee0 | |||
| 210c674f25 | |||
| 175f4330f1 |
@@ -3,6 +3,7 @@ FROM dunglas/frankenphp:php8.4
|
||||
ENV SERVER_NAME=":80"
|
||||
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
|
||||
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
|
||||
ENV APP_VERSION="0.0.1"
|
||||
|
||||
RUN install-php-extensions \
|
||||
pdo_mysql \
|
||||
|
||||
@@ -12,6 +12,7 @@ export default class extends Controller {
|
||||
filename: String,
|
||||
mediaType: String,
|
||||
imdbId: String,
|
||||
episodeId: String
|
||||
}
|
||||
|
||||
download() {
|
||||
@@ -27,6 +28,7 @@ export default class extends Controller {
|
||||
filename: this.filenameValue,
|
||||
mediaType: this.mediaTypeValue,
|
||||
imdbId: this.imdbIdValue,
|
||||
episodeId: this.episodeIdValue
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
|
||||
48
assets/controllers/hamburger_controller.js
Normal file
48
assets/controllers/hamburger_controller.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import { Controller } from '@hotwired/stimulus';
|
||||
|
||||
/*
|
||||
* The following line makes this controller "lazy": it won't be downloaded until needed
|
||||
* See https://symfony.com/bundles/StimulusBundle/current/index.html#lazy-stimulus-controllers
|
||||
*/
|
||||
|
||||
/* stimulusFetch: 'lazy' */
|
||||
export default class extends Controller {
|
||||
static outlets = ['navbar']
|
||||
|
||||
initialize() {
|
||||
// Called once when the controller is first instantiated (per element)
|
||||
|
||||
// Here you can initialize variables, create scoped callables for event
|
||||
// listeners, instantiate external libraries, etc.
|
||||
// this._fooBar = this.fooBar.bind(this)
|
||||
}
|
||||
|
||||
connect() {
|
||||
// Called every time the controller is connected to the DOM
|
||||
// (on page load, when it's added to the DOM, moved in the DOM, etc.)
|
||||
|
||||
// Here you can add event listeners on the element or target elements,
|
||||
// add or remove classes, attributes, dispatch custom events, etc.
|
||||
// this.fooTarget.addEventListener('click', this._fooBar)
|
||||
}
|
||||
|
||||
navbarOutletConnected(outlet) {
|
||||
console.log(outlet)
|
||||
}
|
||||
|
||||
toggleMenu() {
|
||||
console.log(this.navbarOutlet);
|
||||
this.navbarOutlet.toggle();
|
||||
}
|
||||
|
||||
// Add custom controller actions here
|
||||
// fooBar() { this.fooTarget.classList.toggle(this.bazClass) }
|
||||
|
||||
disconnect() {
|
||||
// Called anytime its element is disconnected from the DOM
|
||||
// (on page change, when it's removed from or moved in the DOM, etc.)
|
||||
|
||||
// Here you should remove all event listeners added in "connect()"
|
||||
// this.fooTarget.removeEventListener('click', this._fooBar)
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,15 @@ export default class extends Controller {
|
||||
link.className = this.activeStyles;
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("resize", (event) => {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
setActive() {
|
||||
|
||||
toggle() {
|
||||
this.element.parentElement.classList.toggle('hidden');
|
||||
this.element.classList.toggle('fixed');
|
||||
this.element.classList.toggle('z-20');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export default class extends Controller {
|
||||
active: Boolean,
|
||||
};
|
||||
|
||||
static targets = ['list', 'count', 'episodeSelector', 'toggleButton']
|
||||
static targets = ['list', 'count', 'episodeSelector', 'toggleButton', 'listContainer']
|
||||
static outlets = ['loading-icon']
|
||||
|
||||
options = []
|
||||
@@ -32,19 +32,29 @@ export default class extends Controller {
|
||||
async setOptions() {
|
||||
if (this.optionsLoaded === false) {
|
||||
this.optionsLoaded = true;
|
||||
await fetch(`/torrentio/tvshows/${this.tmdbIdValue}/${this.imdbIdValue}/${this.seasonValue}/${this.episodeValue}`)
|
||||
.then(res => res.text())
|
||||
.then(response => {
|
||||
this.element.innerHTML = response;
|
||||
this.options = this.element.querySelectorAll('tbody tr');
|
||||
if (this.options.length > 0) {
|
||||
this.options.forEach((option) => option.querySelector('.download-btn').dataset['title'] = this.titleValue);
|
||||
this.options[0].querySelector('input[type="checkbox"]').checked = true;
|
||||
} else {
|
||||
this.episodeSelectorTarget.disabled = true;
|
||||
}
|
||||
this.loadingIconOutlet.increaseCount();
|
||||
});
|
||||
let response;
|
||||
|
||||
try {
|
||||
response = await fetch(`/torrentio/tvshows/${this.tmdbIdValue}/${this.imdbIdValue}/${this.seasonValue}/${this.episodeValue}`)
|
||||
} catch (error) {
|
||||
console.log('There was an error', error);
|
||||
}
|
||||
|
||||
if (response?.ok) {
|
||||
response = await response.text()
|
||||
this.listContainerTarget.innerHTML = response;
|
||||
this.options = this.element.querySelectorAll('tbody tr');
|
||||
if (this.options.length > 0) {
|
||||
this.options.forEach((option) => option.querySelector('.download-btn').dataset['title'] = this.titleValue);
|
||||
this.options[0].querySelector('input[type="checkbox"]').checked = true;
|
||||
} else {
|
||||
this.countTarget.innerText = 0;
|
||||
this.episodeSelectorTarget.disabled = true;
|
||||
}
|
||||
this.loadingIconOutlet.increaseCount();
|
||||
} else {
|
||||
console.log(`HTTP Response Code: ${response?.status}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,13 +90,7 @@ export default class extends Controller {
|
||||
}
|
||||
|
||||
toggleList() {
|
||||
// if (!this.isOpen) {
|
||||
// this.toggleButtonTarget.classList.add('rotate-180');
|
||||
// this.toggleButtonTarget.classList.remove('-rotate-180');
|
||||
// } else {
|
||||
// this.toggleButtonTarget.classList.add('-rotate-180');
|
||||
// this.toggleButtonTarget.classList.remove('rotate-180');
|
||||
// }
|
||||
this.listTarget.classList.toggle('options-table');
|
||||
this.listTarget.classList.toggle('hidden');
|
||||
this.toggleButtonTarget.classList.toggle('rotate-90');
|
||||
this.toggleButtonTarget.classList.toggle('-rotate-90');
|
||||
|
||||
1
assets/icons/pajamas/hamburger.svg
Normal file
1
assets/icons/pajamas/hamburger.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 0 0"><path fill="currentColor" fill-rule="evenodd" d="M0 3.75A.75.75 0 0 1 .75 3h14.5a.75.75 0 0 1 0 1.5H.75A.75.75 0 0 1 0 3.75M0 8a.75.75 0 0 1 .75-.75h14.5a.75.75 0 0 1 0 1.5H.75A.75.75 0 0 1 0 8m.75 3.5a.75.75 0 0 0 0 1.5h14.5a.75.75 0 0 0 0-1.5z" clip-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 333 B |
@@ -15,6 +15,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.alert {
|
||||
@apply text-white text-sm min-w-[250px] border px-4 py-3 rounded-md
|
||||
}
|
||||
.alert-success {
|
||||
@apply bg-green-950 hover:bg-green-900 border-green-500
|
||||
}
|
||||
.alert-warning {
|
||||
@apply bg-yellow-500/70 hover:bg-yellow-600 border-yellow-400 text-black
|
||||
}
|
||||
}
|
||||
|
||||
/* Prevent scrolling while dialog is open */
|
||||
body:has(dialog[data-dialog-target="dialog"][open]) {
|
||||
overflow: hidden;
|
||||
@@ -51,3 +63,17 @@ dialog[data-dialog-target="dialog"][open] {
|
||||
dialog[data-dialog-target="dialog"][closing] {
|
||||
animation: fade-out 200ms forwards;
|
||||
}
|
||||
|
||||
.options-table {
|
||||
display: flex;
|
||||
|
||||
:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.options-table {
|
||||
display: inline-table;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
"doctrine/doctrine-migrations-bundle": "^3.4",
|
||||
"doctrine/orm": "^3.3",
|
||||
"dragonmantank/cron-expression": "^3.4",
|
||||
"guzzlehttp/guzzle": "^7.9",
|
||||
"league/pipeline": "^1.1",
|
||||
"nesbot/carbon": "^3.9",
|
||||
"nihilarr/parse-torrent-name": "^0.0.1",
|
||||
"nyholm/psr7": "*",
|
||||
"p3k/emoji-detector": "^1.2",
|
||||
"php-http/cache-plugin": "^2.0",
|
||||
"php-tmdb/api": "^4.1",
|
||||
"predis/predis": "^2.4",
|
||||
"runtime/frankenphp-symfony": "^0.2.0",
|
||||
|
||||
739
composer.lock
generated
739
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "e8b5e39f9d73a6ace2b9e39240186b4f",
|
||||
"content-hash": "67e697578f7237f60726c0d93bfed001",
|
||||
"packages": [
|
||||
{
|
||||
"name": "1tomany/rich-bundle",
|
||||
@@ -285,6 +285,72 @@
|
||||
},
|
||||
"time": "2021-10-17T22:52:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "clue/stream-filter",
|
||||
"version": "v1.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/clue/stream-filter.git",
|
||||
"reference": "049509fef80032cb3f051595029ab75b49a3c2f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/clue/stream-filter/zipball/049509fef80032cb3f051595029ab75b49a3c2f7",
|
||||
"reference": "049509fef80032cb3f051595029ab75b49a3c2f7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Clue\\StreamFilter\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering"
|
||||
}
|
||||
],
|
||||
"description": "A simple and modern approach to stream filtering in PHP",
|
||||
"homepage": "https://github.com/clue/stream-filter",
|
||||
"keywords": [
|
||||
"bucket brigade",
|
||||
"callback",
|
||||
"filter",
|
||||
"php_user_filter",
|
||||
"stream",
|
||||
"stream_filter_append",
|
||||
"stream_filter_register"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/clue/stream-filter/issues",
|
||||
"source": "https://github.com/clue/stream-filter/tree/v1.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://clue.engineering/support",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/clue",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-12-20T15:40:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
"version": "3.4.3",
|
||||
@@ -1947,6 +2013,331 @@
|
||||
],
|
||||
"time": "2025-04-04T17:19:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "7.9.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/guzzle.git",
|
||||
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
|
||||
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"guzzlehttp/promises": "^1.5.3 || ^2.0.3",
|
||||
"guzzlehttp/psr7": "^2.7.0",
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"symfony/deprecation-contracts": "^2.2 || ^3.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-client-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"ext-curl": "*",
|
||||
"guzzle/client-integration-tests": "3.0.2",
|
||||
"php-http/message-factory": "^1.1",
|
||||
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
|
||||
"psr/log": "^1.1 || ^2.0 || ^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": "Required for CURL handler support",
|
||||
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
|
||||
"psr/log": "Required for using the Log middleware"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
},
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
},
|
||||
{
|
||||
"name": "Jeremy Lindblom",
|
||||
"email": "jeremeamia@gmail.com",
|
||||
"homepage": "https://github.com/jeremeamia"
|
||||
},
|
||||
{
|
||||
"name": "George Mponos",
|
||||
"email": "gmponos@gmail.com",
|
||||
"homepage": "https://github.com/gmponos"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
},
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com",
|
||||
"homepage": "https://github.com/sagikazarmark"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Schultze",
|
||||
"email": "webmaster@tubo-world.de",
|
||||
"homepage": "https://github.com/Tobion"
|
||||
}
|
||||
],
|
||||
"description": "Guzzle is a PHP HTTP client library",
|
||||
"keywords": [
|
||||
"client",
|
||||
"curl",
|
||||
"framework",
|
||||
"http",
|
||||
"http client",
|
||||
"psr-18",
|
||||
"psr-7",
|
||||
"rest",
|
||||
"web service"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/guzzle/issues",
|
||||
"source": "https://github.com/guzzle/guzzle/tree/7.9.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/Nyholm",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-03-27T13:37:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
"version": "2.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/promises.git",
|
||||
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c",
|
||||
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Promise\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
},
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Schultze",
|
||||
"email": "webmaster@tubo-world.de",
|
||||
"homepage": "https://github.com/Tobion"
|
||||
}
|
||||
],
|
||||
"description": "Guzzle promises library",
|
||||
"keywords": [
|
||||
"promise"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/promises/issues",
|
||||
"source": "https://github.com/guzzle/promises/tree/2.2.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/Nyholm",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-03-27T13:27:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"version": "2.7.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/psr7.git",
|
||||
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16",
|
||||
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"psr/http-factory": "^1.0",
|
||||
"psr/http-message": "^1.1 || ^2.0",
|
||||
"ralouphie/getallheaders": "^3.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-factory-implementation": "1.0",
|
||||
"psr/http-message-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"http-interop/http-factory-tests": "0.9.0",
|
||||
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
|
||||
},
|
||||
"suggest": {
|
||||
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Psr7\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
},
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
},
|
||||
{
|
||||
"name": "George Mponos",
|
||||
"email": "gmponos@gmail.com",
|
||||
"homepage": "https://github.com/gmponos"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
},
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com",
|
||||
"homepage": "https://github.com/sagikazarmark"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Schultze",
|
||||
"email": "webmaster@tubo-world.de",
|
||||
"homepage": "https://github.com/Tobion"
|
||||
},
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com",
|
||||
"homepage": "https://sagikazarmark.hu"
|
||||
}
|
||||
],
|
||||
"description": "PSR-7 message implementation that also provides common utility methods",
|
||||
"keywords": [
|
||||
"http",
|
||||
"message",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response",
|
||||
"stream",
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/psr7/issues",
|
||||
"source": "https://github.com/guzzle/psr7/tree/2.7.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/Nyholm",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-03-27T12:30:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lcobucci/jwt",
|
||||
"version": "5.5.0",
|
||||
@@ -2540,6 +2931,130 @@
|
||||
},
|
||||
"time": "2024-02-19T18:29:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/cache-plugin",
|
||||
"version": "2.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/cache-plugin.git",
|
||||
"reference": "5c591e9e04602cec12307e3e1be3abefeb005e29"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/cache-plugin/zipball/5c591e9e04602cec12307e3e1be3abefeb005e29",
|
||||
"reference": "5c591e9e04602cec12307e3e1be3abefeb005e29",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0",
|
||||
"php-http/client-common": "^1.9 || ^2.0",
|
||||
"psr/cache": "^1.0 || ^2.0 || ^3.0",
|
||||
"psr/http-factory-implementation": "^1.0",
|
||||
"symfony/options-resolver": "^2.6 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nyholm/psr7": "^1.6.1",
|
||||
"phpspec/phpspec": "^5.1 || ^6.0 || ^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Http\\Client\\Common\\Plugin\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "PSR-6 Cache plugin for HTTPlug",
|
||||
"homepage": "http://httplug.io",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"http",
|
||||
"httplug",
|
||||
"plugin"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/cache-plugin/issues",
|
||||
"source": "https://github.com/php-http/cache-plugin/tree/2.0.1"
|
||||
},
|
||||
"time": "2024-10-02T11:25:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/client-common",
|
||||
"version": "2.7.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/client-common.git",
|
||||
"reference": "0cfe9858ab9d3b213041b947c881d5b19ceeca46"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/client-common/zipball/0cfe9858ab9d3b213041b947c881d5b19ceeca46",
|
||||
"reference": "0cfe9858ab9d3b213041b947c881d5b19ceeca46",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0",
|
||||
"php-http/httplug": "^2.0",
|
||||
"php-http/message": "^1.6",
|
||||
"psr/http-client": "^1.0",
|
||||
"psr/http-factory": "^1.0",
|
||||
"psr/http-message": "^1.0 || ^2.0",
|
||||
"symfony/options-resolver": "~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/polyfill-php80": "^1.17"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/instantiator": "^1.1",
|
||||
"guzzlehttp/psr7": "^1.4",
|
||||
"nyholm/psr7": "^1.2",
|
||||
"phpspec/phpspec": "^5.1 || ^6.3 || ^7.1",
|
||||
"phpspec/prophecy": "^1.10.2",
|
||||
"phpunit/phpunit": "^7.5.20 || ^8.5.33 || ^9.6.7"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-json": "To detect JSON responses with the ContentTypePlugin",
|
||||
"ext-libxml": "To detect XML responses with the ContentTypePlugin",
|
||||
"php-http/cache-plugin": "PSR-6 Cache plugin",
|
||||
"php-http/logger-plugin": "PSR-3 Logger plugin",
|
||||
"php-http/stopwatch-plugin": "Symfony Stopwatch plugin"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Http\\Client\\Common\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Common HTTP Client implementations and tools for HTTPlug",
|
||||
"homepage": "http://httplug.io",
|
||||
"keywords": [
|
||||
"client",
|
||||
"common",
|
||||
"http",
|
||||
"httplug"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/client-common/issues",
|
||||
"source": "https://github.com/php-http/client-common/tree/2.7.2"
|
||||
},
|
||||
"time": "2024-09-24T06:21:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/discovery",
|
||||
"version": "1.20.0",
|
||||
@@ -2619,6 +3134,184 @@
|
||||
},
|
||||
"time": "2024-10-02T11:20:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/httplug",
|
||||
"version": "2.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/httplug.git",
|
||||
"reference": "5cad731844891a4c282f3f3e1b582c46839d22f4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/httplug/zipball/5cad731844891a4c282f3f3e1b582c46839d22f4",
|
||||
"reference": "5cad731844891a4c282f3f3e1b582c46839d22f4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0",
|
||||
"php-http/promise": "^1.1",
|
||||
"psr/http-client": "^1.0",
|
||||
"psr/http-message": "^1.0 || ^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friends-of-phpspec/phpspec-code-coverage": "^4.1 || ^5.0 || ^6.0",
|
||||
"phpspec/phpspec": "^5.1 || ^6.0 || ^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Http\\Client\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Eric GELOEN",
|
||||
"email": "geloen.eric@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com",
|
||||
"homepage": "https://sagikazarmark.hu"
|
||||
}
|
||||
],
|
||||
"description": "HTTPlug, the HTTP client abstraction for PHP",
|
||||
"homepage": "http://httplug.io",
|
||||
"keywords": [
|
||||
"client",
|
||||
"http"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/httplug/issues",
|
||||
"source": "https://github.com/php-http/httplug/tree/2.4.1"
|
||||
},
|
||||
"time": "2024-09-23T11:39:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/message",
|
||||
"version": "1.16.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/message.git",
|
||||
"reference": "06dd5e8562f84e641bf929bfe699ee0f5ce8080a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/message/zipball/06dd5e8562f84e641bf929bfe699ee0f5ce8080a",
|
||||
"reference": "06dd5e8562f84e641bf929bfe699ee0f5ce8080a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"clue/stream-filter": "^1.5",
|
||||
"php": "^7.2 || ^8.0",
|
||||
"psr/http-message": "^1.1 || ^2.0"
|
||||
},
|
||||
"provide": {
|
||||
"php-http/message-factory-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ergebnis/composer-normalize": "^2.6",
|
||||
"ext-zlib": "*",
|
||||
"guzzlehttp/psr7": "^1.0 || ^2.0",
|
||||
"laminas/laminas-diactoros": "^2.0 || ^3.0",
|
||||
"php-http/message-factory": "^1.0.2",
|
||||
"phpspec/phpspec": "^5.1 || ^6.3 || ^7.1",
|
||||
"slim/slim": "^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-zlib": "Used with compressor/decompressor streams",
|
||||
"guzzlehttp/psr7": "Used with Guzzle PSR-7 Factories",
|
||||
"laminas/laminas-diactoros": "Used with Diactoros Factories",
|
||||
"slim/slim": "Used with Slim Framework PSR-7 implementation"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/filters.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Http\\Message\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "HTTP Message related tools",
|
||||
"homepage": "http://php-http.org",
|
||||
"keywords": [
|
||||
"http",
|
||||
"message",
|
||||
"psr-7"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/message/issues",
|
||||
"source": "https://github.com/php-http/message/tree/1.16.2"
|
||||
},
|
||||
"time": "2024-10-02T11:34:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/promise",
|
||||
"version": "1.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/promise.git",
|
||||
"reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/promise/zipball/fc85b1fba37c169a69a07ef0d5a8075770cc1f83",
|
||||
"reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friends-of-phpspec/phpspec-code-coverage": "^4.3.2 || ^6.3",
|
||||
"phpspec/phpspec": "^5.1.2 || ^6.2 || ^7.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Http\\Promise\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Joel Wurtz",
|
||||
"email": "joel.wurtz@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Promise used for asynchronous HTTP requests",
|
||||
"homepage": "http://httplug.io",
|
||||
"keywords": [
|
||||
"promise"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/promise/issues",
|
||||
"source": "https://github.com/php-http/promise/tree/1.3.1"
|
||||
},
|
||||
"time": "2024-03-15T13:55:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-tmdb/api",
|
||||
"version": "4.1.3",
|
||||
@@ -3527,6 +4220,50 @@
|
||||
},
|
||||
"time": "2021-10-29T13:26:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ralouphie/getallheaders",
|
||||
"version": "3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ralouphie/getallheaders.git",
|
||||
"reference": "120b605dfeb996808c31b6477290a714d356e822"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
|
||||
"reference": "120b605dfeb996808c31b6477290a714d356e822",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-coveralls/php-coveralls": "^2.1",
|
||||
"phpunit/phpunit": "^5 || ^6.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/getallheaders.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ralph Khattar",
|
||||
"email": "ralph.khattar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A polyfill for getallheaders.",
|
||||
"support": {
|
||||
"issues": "https://github.com/ralouphie/getallheaders/issues",
|
||||
"source": "https://github.com/ralouphie/getallheaders/tree/develop"
|
||||
},
|
||||
"time": "2019-03-08T08:55:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "runtime/frankenphp-symfony",
|
||||
"version": "0.2.0",
|
||||
|
||||
@@ -11,7 +11,7 @@ framework:
|
||||
trusted_headers: [ 'x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix' ]
|
||||
|
||||
session:
|
||||
handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
|
||||
handler_id: '%env(REDIS_HOST)%'
|
||||
|
||||
#esi: true
|
||||
#fragments: true
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
twig:
|
||||
globals:
|
||||
version: '%app.version%'
|
||||
file_name_pattern: '*.twig'
|
||||
date:
|
||||
format: 'm/d/Y'
|
||||
timezone: '%env(default:app.default.timezone:TZ)%'
|
||||
|
||||
when@test:
|
||||
|
||||
@@ -22,8 +22,11 @@ parameters:
|
||||
app.cache.redis.host.default: 'redis://redis'
|
||||
|
||||
# Various configs
|
||||
app.default.version: '0.dev'
|
||||
app.default.timezone: 'America/Chicago'
|
||||
|
||||
app.version: '%env(default:app.default.version:APP_VERSION)%'
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
_defaults:
|
||||
|
||||
@@ -4,6 +4,9 @@ ENV SERVER_NAME=":80"
|
||||
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
|
||||
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
|
||||
|
||||
ARG APP_VERSION="0.dev"
|
||||
ENV APP_VERSION="${APP_VERSION}"
|
||||
|
||||
RUN install-php-extensions \
|
||||
pdo_mysql \
|
||||
gd \
|
||||
|
||||
@@ -4,6 +4,9 @@ ENV SERVER_NAME=":80"
|
||||
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
|
||||
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
|
||||
|
||||
ARG APP_VERSION="0.dev"
|
||||
ENV APP_VERSION="${APP_VERSION}"
|
||||
|
||||
RUN install-php-extensions \
|
||||
pdo_mysql \
|
||||
gd \
|
||||
|
||||
@@ -4,6 +4,9 @@ ENV SERVER_NAME=":80"
|
||||
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
|
||||
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
|
||||
|
||||
ARG APP_VERSION="0.dev"
|
||||
ENV APP_VERSION="${APP_VERSION}"
|
||||
|
||||
RUN install-php-extensions \
|
||||
pdo_mysql \
|
||||
gd \
|
||||
|
||||
@@ -27,7 +27,7 @@ DATABASE_URL="mysql://root:password@database:3306/app?serverVersion=10.6.19.2-Ma
|
||||
# Popular Movies and TV Shows section.
|
||||
#TMDB_API=
|
||||
|
||||
REAL_DEBRID_KEY="QYYBR7OSQ4VEFKWASDEZ2B4VO67KHUJY6IWOT7HHA7ATXO7QCYDQ"
|
||||
REAL_DEBRID_KEY=""
|
||||
TMDB_API=eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI0ZTJjYjJhOGUzOGJhNjdiNjVhOGU1NGM0ZWI1MzhmOCIsIm5iZiI6MTczNzkyNjA0NC41NjQsInN1YiI6IjY3OTZhNTljYzdiMDFiNzJjNzIzZWM5YiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.e8DbNe9qrSBC1y-ANRv-VWBAtls-ZS2r7aNCiI68mpw
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,13 @@ services:
|
||||
- '8006:80'
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- /mnt/media/downloads/movies:/var/download/movies
|
||||
- /mnt/media/downloads/tvshows:/var/download/tvshows
|
||||
environment:
|
||||
TZ: America/Chicago
|
||||
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
||||
MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
@@ -27,6 +34,8 @@ services:
|
||||
volumes:
|
||||
- /mnt/media/downloads/movies:/var/download/movies
|
||||
- /mnt/media/downloads/tvshows:/var/download/tvshows
|
||||
environment:
|
||||
TZ: America/Chicago
|
||||
command: -vvv
|
||||
env_file:
|
||||
- .env
|
||||
@@ -43,35 +52,17 @@ services:
|
||||
scheduler:
|
||||
image: code.caldwell.digital/home/torsearch-scheduler:latest
|
||||
volumes:
|
||||
- ./downloads:/var/download
|
||||
- /mnt/media/downloads/movies:/var/download/movies
|
||||
- /mnt/media/downloads/tvshows:/var/download/tvshows
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
TZ: America/Chicago
|
||||
restart: always
|
||||
depends_on:
|
||||
app:
|
||||
condition: service_healthy
|
||||
|
||||
# This container facilitates viewing the progress of downloads
|
||||
# in realtime. It also handles sending alerts and notifications.
|
||||
# The MERCURE_PUBLISHER_JWT key & MERCURE_SUBSCRIBER_JWT_KEY should
|
||||
# match the MERCURE_JWT_SECRET environment variable.
|
||||
mercure:
|
||||
image: dunglas/mercure
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3001:80"
|
||||
environment:
|
||||
SERVER_NAME: ':80'
|
||||
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
||||
MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
||||
MERCURE_EXTRA_DIRECTIVES: |
|
||||
cors_origins *
|
||||
anonymous
|
||||
command: /usr/bin/caddy run --config /etc/caddy/dev.Caddyfile
|
||||
volumes:
|
||||
- mercure_data:/data
|
||||
- mercure_config:/config
|
||||
|
||||
database:
|
||||
image: mariadb:10.11.2
|
||||
volumes:
|
||||
|
||||
@@ -40,4 +40,11 @@ return [
|
||||
'stimulus-use' => [
|
||||
'version' => '0.52.2',
|
||||
],
|
||||
'animate.css' => [
|
||||
'version' => '4.1.1',
|
||||
],
|
||||
'animate.css/animate.min.css' => [
|
||||
'version' => '4.1.1',
|
||||
'type' => 'css',
|
||||
],
|
||||
];
|
||||
|
||||
@@ -40,8 +40,6 @@ final class SearchController extends AbstractController
|
||||
): Response {
|
||||
$result = $this->getMediaInfoHandler->handle($input->toCommand());
|
||||
|
||||
// $this->warmDownloadOptionCache($result->media);
|
||||
|
||||
return $this->render('search/result.html.twig', [
|
||||
'results' => $result,
|
||||
'filter' => [
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Torrentio\Action\Handler\GetMovieOptionsHandler;
|
||||
use App\Torrentio\Action\Handler\GetTvShowOptionsHandler;
|
||||
use App\Torrentio\Action\Input\GetMovieOptionsInput;
|
||||
use App\Torrentio\Action\Input\GetTvShowOptionsInput;
|
||||
use App\Torrentio\Exception\TorrentioRateLimitException;
|
||||
use App\Util\Broadcaster;
|
||||
use Carbon\Carbon;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
@@ -52,13 +53,24 @@ final class TorrentioController extends AbstractController
|
||||
$input->episode,
|
||||
);
|
||||
|
||||
return $cache->get($cacheId, function (ItemInterface $item) use ($input) {
|
||||
$item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0));
|
||||
$results = $this->getTvShowOptionsHandler->handle($input->toCommand());
|
||||
return $this->render('torrentio/tvshows.html.twig', [
|
||||
'results' => $results,
|
||||
]);
|
||||
});
|
||||
try {
|
||||
return $cache->get($cacheId, function (ItemInterface $item) use ($input) {
|
||||
$item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0));
|
||||
$results = $this->getTvShowOptionsHandler->handle($input->toCommand());
|
||||
return $this->render('torrentio/tvshows.html.twig', [
|
||||
'results' => $results,
|
||||
]);
|
||||
});
|
||||
} catch (TorrentioRateLimitException $exception) {
|
||||
$this->broadcaster->alert('Warning', 'Torrentio has rate limited your requests. Please wait a few minutes before trying again.', 'warning');
|
||||
return $this->render('bare.html.twig',
|
||||
[],
|
||||
new Response('Too many requests',
|
||||
Response::HTTP_TOO_MANY_REQUESTS,
|
||||
['Retry-After' => 4000]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[Route('/torrentio/tvshows/clear/{tmdbId}/{imdbId}/{season?}/{episode?}', name: 'app_clear_torrentio_tvshows')]
|
||||
|
||||
@@ -26,6 +26,9 @@ class DownloadMediaInput implements InputInterface
|
||||
#[SourceRequest('imdbId')]
|
||||
public string $imdbId,
|
||||
|
||||
#[SourceRequest('episodeId', nullify: true)]
|
||||
public ?string $episodeId = null,
|
||||
|
||||
public ?int $userId = null,
|
||||
|
||||
public ?int $downloadId = null,
|
||||
|
||||
@@ -11,6 +11,7 @@ use App\Download\Action\Input\PauseDownloadInput;
|
||||
use App\Download\Action\Input\ResumeDownloadInput;
|
||||
use App\Download\Framework\Repository\DownloadRepository;
|
||||
use App\Util\Broadcaster;
|
||||
use Nihilarr\PTN;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
@@ -28,6 +29,13 @@ class ApiController extends AbstractController
|
||||
public function download(
|
||||
DownloadMediaInput $input,
|
||||
): Response {
|
||||
$ptn = (object) new Ptn()->parse($input->filename);
|
||||
if ($input->mediaType === "tvshows" &&
|
||||
!property_exists($ptn, 'episode') && !property_exists($ptn, 'season')
|
||||
) {
|
||||
$input->filename = $input->episodeId . '_' . $input->filename;
|
||||
}
|
||||
|
||||
$download = $this->downloadRepository->insert(
|
||||
$this->getUser(),
|
||||
$input->url,
|
||||
|
||||
@@ -61,10 +61,10 @@ readonly class MonitorTvShowHandler implements HandlerInterface
|
||||
// Dispatch Episode commands for each missing Episode
|
||||
foreach ($episodesInShow as $episode) {
|
||||
// Only monitor future episodes
|
||||
$episodeInFuture = $this->episodeInFuture($episode);
|
||||
$this->logger->info('> [MonitorTvShowHandler] Episode is in future for season ' . $episode['season_number'] . ' episode ' . $episode['episode_number'] . ' for title: ' . $monitor->getTitle() . ' ? ' . (true === $episodeInFuture ? 'YES' : 'NO'));
|
||||
$episodeInFuture = $this->episodeReleasedAfterMonitorCreated($monitor->getCreatedAt(), $episode);
|
||||
$this->logger->info('> [MonitorTvShowHandler] Episode released after monitor started for season ' . $episode['season_number'] . ' episode ' . $episode['episode_number'] . ' for title: ' . $monitor->getTitle() . ' ? ' . (true === $episodeInFuture ? 'YES' : 'NO'));
|
||||
if (false === $episodeInFuture) {
|
||||
$this->logger->info('> [MonitorTvShowHandler] Episode not in future for title: ' . 'for season ' . $episode['season_number'] . ' episode ' . $episode['episode_number'] . ', skipping');
|
||||
$this->logger->info('> [MonitorTvShowHandler] Episode released after monitor started for title: ' . 'for season ' . $episode['season_number'] . ' episode ' . $episode['episode_number'] . ', skipping');
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -125,11 +125,11 @@ readonly class MonitorTvShowHandler implements HandlerInterface
|
||||
);
|
||||
}
|
||||
|
||||
private function episodeInFuture(array $episodeInShow): bool
|
||||
private function episodeReleasedAfterMonitorCreated(string|DateTimeImmutable $monitorStartDate, array $episodeInShow): bool
|
||||
{
|
||||
static $today = Carbon::today();
|
||||
$monitorStartDate = Carbon::parse($monitorStartDate)->setTime(0, 0);
|
||||
$episodeAirDate = Carbon::parse($episodeInShow['air_date']);
|
||||
return $episodeAirDate > $today;
|
||||
return $episodeAirDate >= $monitorStartDate;
|
||||
}
|
||||
|
||||
private function episodeExists(array $episodeInShow, Map $downloadedEpisodes): bool
|
||||
|
||||
@@ -2,17 +2,13 @@
|
||||
|
||||
namespace App\Monitor\Framework\Controller;
|
||||
|
||||
use App\Download\Action\Input\DeleteDownloadInput;
|
||||
use App\Monitor\Action\Handler\AddMonitorHandler;
|
||||
use App\Monitor\Action\Handler\DeleteMonitorHandler;
|
||||
use App\Monitor\Action\Input\AddMonitorInput;
|
||||
use App\Monitor\Action\Input\DeleteMonitorInput;
|
||||
use App\Util\Broadcaster;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\Mercure\HubInterface;
|
||||
use Symfony\Component\Mercure\Update;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class ApiController extends AbstractController
|
||||
@@ -46,19 +42,9 @@ class ApiController extends AbstractController
|
||||
public function deleteMonitor(
|
||||
DeleteMonitorInput $input,
|
||||
DeleteMonitorHandler $handler,
|
||||
HubInterface $hub,
|
||||
) {
|
||||
$response = $handler->handle($input->toCommand());
|
||||
|
||||
$hub->publish(new Update(
|
||||
'alerts',
|
||||
$this->renderer->render('broadcast/Alert.stream.html.twig', [
|
||||
'alert_id' => uniqid(),
|
||||
'title' => 'Success',
|
||||
'message' => "New monitor added for {$response->monitor->getTitle()}",
|
||||
])
|
||||
));
|
||||
|
||||
return $this->json([
|
||||
'status' => 200,
|
||||
'message' => $response
|
||||
|
||||
@@ -5,6 +5,9 @@ namespace App\Tmdb;
|
||||
use Aimeos\Map;
|
||||
use App\Enum\MediaType;
|
||||
use App\ValueObject\ResultFactory;
|
||||
use Carbon\Carbon;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
@@ -12,6 +15,7 @@ use Symfony\Contracts\Cache\ItemInterface;
|
||||
use Tmdb\Api\Find;
|
||||
use Tmdb\Client;
|
||||
use Tmdb\Event\BeforeRequestEvent;
|
||||
use Tmdb\Event\Listener\Psr6CachedRequestListener;
|
||||
use Tmdb\Event\Listener\Request\AcceptJsonRequestListener;
|
||||
use Tmdb\Event\Listener\Request\ApiTokenRequestListener;
|
||||
use Tmdb\Event\Listener\Request\ContentTypeJsonRequestListener;
|
||||
@@ -40,7 +44,7 @@ class Tmdb
|
||||
const POSTER_IMG_PATH = "https://image.tmdb.org/t/p/w500";
|
||||
|
||||
public function __construct(
|
||||
private readonly CacheInterface $cache,
|
||||
private readonly CacheItemPoolInterface $cache,
|
||||
private readonly EventDispatcherInterface $eventDispatcher,
|
||||
#[Autowire(env: 'TMDB_API')] string $apiKey,
|
||||
) {
|
||||
@@ -71,7 +75,13 @@ class Tmdb
|
||||
/**
|
||||
* Required event listeners and events to be registered with the PSR-14 Event Dispatcher.
|
||||
*/
|
||||
$requestListener = new RequestListener($this->client->getHttpClient(), $this->eventDispatcher);
|
||||
$requestListener = new Psr6CachedRequestListener(
|
||||
$this->client->getHttpClient(),
|
||||
$this->eventDispatcher,
|
||||
$cache,
|
||||
$this->client->getHttpClient()->getPsr17StreamFactory(),
|
||||
[]
|
||||
);
|
||||
$this->eventDispatcher->addListener(RequestEvent::class, $requestListener);
|
||||
|
||||
$apiTokenListener = new ApiTokenRequestListener($this->client->getToken());
|
||||
@@ -209,7 +219,12 @@ class Tmdb
|
||||
continue;
|
||||
}
|
||||
|
||||
$series['episodes'][$season['season_number']] = $client->getApi()->getSeason($series['id'], $season['season_number'])['episodes'];
|
||||
$series['episodes'][$season['season_number']] = Map::from(
|
||||
$client->getApi()->getSeason($series['id'], $season['season_number'])['episodes']
|
||||
)->map(function ($data) {
|
||||
$data['poster'] = (null !== $data['still_path']) ? self::POSTER_IMG_PATH . $data['still_path'] : null;
|
||||
return $data;
|
||||
})->toArray();
|
||||
}
|
||||
return $series;
|
||||
}
|
||||
|
||||
@@ -6,34 +6,54 @@ use App\Torrentio\Client\Rule\DownloadOptionFilter\Resolution;
|
||||
use App\Torrentio\Client\Rule\RuleEngine;
|
||||
use App\Torrentio\Result\ResultFactory;
|
||||
use Carbon\Carbon;
|
||||
use App\Torrentio\Exception\TorrentioRateLimitException;
|
||||
use GuzzleHttp\Client;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
use Symfony\Contracts\Cache\TagAwareCacheInterface;
|
||||
|
||||
class Torrentio
|
||||
{
|
||||
private string $baseUrl = 'https://torrentio.strem.fun/providers%253Dyts%252Ceztv%252Crarbg%252C1337x%252Cthepiratebay%252Ckickasstorrents%252Ctorrentgalaxy%252Cmagnetdl%252Chorriblesubs%252Cnyaasi%7Csort%253Dqualitysize%7Cqualityfilter%253D480p%252Cscr%252Ccam%7Crealdebrid={realDebridKey}/stream/movie/{imdbCode}.json';
|
||||
private string $baseUrl = 'https://torrentio.strem.fun/providers%253Dyts%252Ceztv%252Crarbg%252C1337x%252Cthepiratebay%252Ckickasstorrents%252Ctorrentgalaxy%252Cmagnetdl%252Chorriblesubs%252Cnyaasi%7Csort%253Dqualitysize%7Cqualityfilter%253D480p%252Cscr%252Ccam%7Crealdebrid={realDebridKey}/stream/movie';
|
||||
|
||||
private string $searchUrl;
|
||||
|
||||
private Client $client;
|
||||
|
||||
public function __construct(
|
||||
#[Autowire(env: 'REAL_DEBRID_KEY')] private string $realDebridKey,
|
||||
private CacheInterface $cache,
|
||||
private TagAwareCacheInterface $cache,
|
||||
private LoggerInterface $logger,
|
||||
) {
|
||||
$this->searchUrl = str_replace('{realDebridKey}', $this->realDebridKey, $this->baseUrl);
|
||||
$this->client = new Client([
|
||||
'base_uri' => $this->searchUrl,
|
||||
]);
|
||||
}
|
||||
|
||||
public function search(string $imdbCode, string $type, array $filter = []): array
|
||||
{
|
||||
$cacheKey = "torrentio.{$imdbCode}";
|
||||
|
||||
$results = $this->cache->get($cacheKey, function (ItemInterface $item) use ($imdbCode) {
|
||||
$results = $this->cache->get($cacheKey, function (ItemInterface $item) use ($imdbCode, $type) {
|
||||
$item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0));
|
||||
$response = file_get_contents(str_replace('{imdbCode}', $imdbCode, $this->searchUrl));
|
||||
return json_decode(
|
||||
$response,
|
||||
true
|
||||
);
|
||||
$item->tag(['torrentio', $type, $imdbCode]);
|
||||
try {
|
||||
$response = $this->client->get("$this->searchUrl/$imdbCode.json");
|
||||
return json_decode(
|
||||
$response->getBody()->getContents(),
|
||||
true
|
||||
);
|
||||
} catch (\Throwable $exception) {
|
||||
if ($exception->getCode() === 429) {
|
||||
$this->logger->warning("> [TorrentioClient] Rate limit exceeded");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->error("> [TorrentioClient] Request error: " . $response->getStatusCode() . " - " . $response->getBody()->getContents());
|
||||
return [];
|
||||
});
|
||||
|
||||
return $this->parse($results, $filter);
|
||||
@@ -44,13 +64,28 @@ class Torrentio
|
||||
$cacheKey = "torrentio.$imdbId.$season.$episode";
|
||||
$results = $this->cache->get($cacheKey, function (ItemInterface $item) use ($imdbId, $season, $episode) {
|
||||
$item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0));
|
||||
$response = file_get_contents(str_replace('{imdbCode}', "$imdbId:$season:$episode", $this->searchUrl));
|
||||
return json_decode(
|
||||
$response,
|
||||
true
|
||||
);
|
||||
$item->tag(['torrentio', 'tvshows', 'torrentio.tvshows', $imdbId, "torrentio.$imdbId", "$imdbId.$season", "torrentio.$imdbId.$season", "$imdbId.$season.$episode", "torrentio.$imdbId.$season.$episode"]);
|
||||
try {
|
||||
$response = $this->client->get("$this->searchUrl/$imdbId:$season:$episode.json");
|
||||
return json_decode(
|
||||
$response->getBody()->getContents(),
|
||||
true
|
||||
);
|
||||
} catch (\Throwable $exception) {
|
||||
if ($exception->getCode() === 429) {
|
||||
$this->logger->warning("> [TorrentioClient] Rate limit exceeded");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->error("> [TorrentioClient] Request error: " . $response->getStatusCode() . " - " . $response->getBody()->getContents());
|
||||
return [];
|
||||
});
|
||||
|
||||
if (null === $results) {
|
||||
throw new TorrentioRateLimitException();
|
||||
}
|
||||
|
||||
return $this->parse($results, []);
|
||||
}
|
||||
|
||||
|
||||
11
src/Torrentio/Exception/TorrentioRateLimitException.php
Normal file
11
src/Torrentio/Exception/TorrentioRateLimitException.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Torrentio\Exception;
|
||||
|
||||
class TorrentioRateLimitException extends \Exception
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(sprintf("[TorrentioClient] Rate limit exceeded"));
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,10 @@ namespace App\Twig\Extensions;
|
||||
|
||||
use App\Monitor\Framework\Entity\Monitor;
|
||||
use App\Monitor\Service\MediaFiles;
|
||||
use App\Torrentio\Action\Result\GetTvShowOptionsResult;
|
||||
use App\Torrentio\Result\TorrentioResult;
|
||||
use ChrisUllyott\FileSize;
|
||||
use Tmdb\Model\Tv\Episode;
|
||||
use Twig\Attribute\AsTwigFilter;
|
||||
use Twig\Attribute\AsTwigFunction;
|
||||
|
||||
@@ -21,6 +24,15 @@ class UtilExtension
|
||||
return uniqid();
|
||||
}
|
||||
|
||||
#[AsTwigFilter('truncate')]
|
||||
public function truncate(string $text)
|
||||
{
|
||||
if (strlen($text) > 300) {
|
||||
$text = substr($text, 0, 300) . '...';
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
#[AsTwigFilter('filesize')]
|
||||
public function type(string|int $size)
|
||||
{
|
||||
@@ -36,4 +48,15 @@ class UtilExtension
|
||||
$path
|
||||
);
|
||||
}
|
||||
|
||||
#[AsTwigFilter('episode_id_from_results')]
|
||||
public function episodeId($result): ?string
|
||||
{
|
||||
if (!$result instanceof GetTvShowOptionsResult) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return "S". str_pad($result->season, 2, "0", STR_PAD_LEFT) .
|
||||
"E". str_pad($result->episode, 2, "0", STR_PAD_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,16 @@ use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class RegistrationController extends AbstractController
|
||||
{
|
||||
public function __construct(private readonly RegisterUserHandler $registerUserHandler)
|
||||
public function __construct(private readonly RegisterUserHandler $registerUserHandler,
|
||||
private readonly RequestStack $requestStack
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -71,6 +74,7 @@ class RegistrationController extends AbstractController
|
||||
));
|
||||
|
||||
$security->login($user->user);
|
||||
$this->requestStack->getCurrentRequest()->getSession()->set('mercure_alert_topic', 'alerts_' . uniqid());
|
||||
|
||||
return $this->redirectToRoute('app_index');
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ readonly class Broadcaster
|
||||
private RequestStack $requestStack,
|
||||
) {}
|
||||
|
||||
public function alert(string $title, string $message): void
|
||||
public function alert(string $title, string $message, string $type = "success"): void
|
||||
{
|
||||
$userAlertTopic = $this->requestStack->getCurrentRequest()->getSession()->get('mercure_alert_topic');
|
||||
$update = new Update(
|
||||
@@ -26,6 +26,7 @@ readonly class Broadcaster
|
||||
'alert_id' => uniqid(),
|
||||
'title' => $title,
|
||||
'message' => $message,
|
||||
'type' => $type,
|
||||
])
|
||||
);
|
||||
$this->hub->publish($update);
|
||||
|
||||
@@ -13,6 +13,8 @@ module.exports = {
|
||||
"bg-orange-400",
|
||||
"bg-blue-600",
|
||||
"bg-rose-600",
|
||||
"alert-success",
|
||||
"alert-warning",
|
||||
"min-w-64",
|
||||
"rotate-180",
|
||||
"-rotate-180",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
||||
{% block stylesheets %}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
||||
{% block stylesheets %}
|
||||
@@ -13,11 +14,11 @@
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body class="flex flex-col bg-stone-700">
|
||||
<div class="grid grid-cols-6">
|
||||
<div class="col-span-1 h-screen">
|
||||
<div class="grid md:grid-cols-6">
|
||||
<div class="hidden md:block md:col-span-1 md:h-screen">
|
||||
<twig:NavBar />
|
||||
</div>
|
||||
<div class="col-span-5 h-screen overflow-y-scroll">
|
||||
<div class="col-span-6 md:col-span-5 h-screen overflow-y-scroll">
|
||||
<twig:Header />
|
||||
<h2 class="px-4 my-2 text-3xl font-bold text-gray-50">{% block h2 %}{% endblock %}</h2>
|
||||
{% block body %}{% endblock %}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<turbo-stream action="prepend" target="alert_list">
|
||||
<template>
|
||||
<twig:Alert :title="title|default('')" :message="message" :alert_id="alert_id" data-controller="alert" />
|
||||
<twig:Alert :title="title|default('')" :message="message" :alert_id="alert_id" type="{{ type|default('success') }}" data-controller="alert" />
|
||||
</template>
|
||||
</turbo-stream>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<li {{ attributes }} id="alert_{{ alert_id }}" class="
|
||||
text-white bg-green-950 text-sm min-w-[250px]
|
||||
hover:bg-green-900 border border-green-500 px-4 py-3
|
||||
rounded-md"
|
||||
<li {{ attributes }} id="alert_{{ alert_id }}"
|
||||
class="alert alert-{{ type|default('success') }}"
|
||||
role="alert"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
data-result-filter-tv-results-outlet=".results"
|
||||
data-result-filter-tv-episode-list-outlet=".episode-list"
|
||||
>
|
||||
<div class="w-full p-4 flex flex-row gap-4 bg-stone-500 text-md text-gray-500 dark:text-gray-50 rounded-lg">
|
||||
<div class="w-full p-4 flex flex-col md:flex-row gap-4 bg-stone-500 text-md text-gray-500 dark:text-gray-50 rounded-lg">
|
||||
<label for="resolution">
|
||||
Resolution
|
||||
<select id="resolution"
|
||||
|
||||
@@ -5,12 +5,21 @@
|
||||
<div class="md:flex md:items-center md:gap-12">
|
||||
<nav aria-label="Global" class="md:block">
|
||||
<ul class="flex items-center gap-6 text-sm">
|
||||
<li><twig:ux:icon name="fluent:alert-12-regular" width="30px" class="text-gray-950 bg-orange-500 rounded-full p-2"/></li>
|
||||
<li>
|
||||
<li class="hidden">
|
||||
<twig:ux:icon name="fluent:alert-12-regular" width="30px" class="text-gray-950 bg-orange-500 rounded-full p-2"/>
|
||||
</li>
|
||||
<li class="hidden md:block">
|
||||
<a href="{{ path('app_logout') }}">
|
||||
<twig:ux:icon name="material-symbols:logout" width="25px" class="text-orange-500" />
|
||||
</a>
|
||||
</li>
|
||||
<li {{ stimulus_controller('hamburger') }}
|
||||
{{ stimulus_action('hamburger', 'toggleMenu', 'click') }}
|
||||
data-hamburger-navbar-outlet="#navbar"
|
||||
id="hamburger" class="cursor-pointer md:hidden"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="text-orange-500 ml-4" width="25px" height="25px" viewBox="0 0 16 16"><path fill="currentColor" fill-rule="evenodd" d="M0 3.75A.75.75 0 0 1 .75 3h14.5a.75.75 0 0 1 0 1.5H.75A.75.75 0 0 1 0 3.75M0 8a.75.75 0 0 1 .75-.75h14.5a.75.75 0 0 1 0 1.5H.75A.75.75 0 0 1 0 8m.75 3.5a.75.75 0 0 0 0 1.5h14.5a.75.75 0 0 0 0-1.5z" clip-rule="evenodd"/></svg>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<nav {{ attributes }} {{ stimulus_controller('navbar') }} {{ stimulus_action('navbar', 'setActive')}} class="flex h-screen flex-col justify-between bg-cyan-950">
|
||||
<nav id="navbar" {{ attributes }} {{ stimulus_controller('navbar') }} {{ stimulus_action('navbar', 'setActive')}} class="flex h-screen flex-col justify-between bg-cyan-950 animate__animated animate__slideInLeft animate__slow">
|
||||
<div class="px-4 py-4 flex flex-col gap-12">
|
||||
<h1 class="text-3xl font-extrabold text-orange-500 mb-3">Torsearch</h1>
|
||||
<ul class="space-y-1">
|
||||
@@ -38,13 +38,13 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="sticky inset-x-0 bottom-0 border-t border-orange-500">
|
||||
<a href="#" class="nav-foot flex items-center gap-2 p-4 bg-orange-500 hover:bg-opacity-80 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60">
|
||||
<div class="sticky inset-x-0 bottom-0 border-t border-b border-orange-500 bg-orange-500 hover:bg-opacity-80 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60 flex flex-col">
|
||||
<a href="#" class="nav-foot flex items-center gap-2 pt-4 px-4">
|
||||
<span class="rounded-full p-2 border-orange-500 border-2">
|
||||
<twig:ux:icon name="ri:user-line" width="30" class="text-gray-50"/>
|
||||
</span>
|
||||
|
||||
<div>
|
||||
<div class="flex flex-col text-white">
|
||||
<p class="text-xs">
|
||||
{% if app.user.name %}
|
||||
<strong class="block font-medium text-white">{{ app.user.name }}</strong>
|
||||
@@ -54,5 +54,8 @@
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
<p class="px-4 pt-1 inline-flex justify-center">
|
||||
<small class="text-white text-xs">v{{ version|default('0.0') }}</small>
|
||||
</p>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
mediaType: mediaType,
|
||||
imdbId: imdbId
|
||||
}) }}">
|
||||
<img src="{{ image }}" class="w-40 rounded-md" />
|
||||
<img src="{{ image }}" class="w-full md:w-40 rounded-md" />
|
||||
</a>
|
||||
<a href="{{ path('app_search_result', {
|
||||
mediaType: mediaType,
|
||||
imdbId: imdbId
|
||||
}) }}">
|
||||
<h3 class="text-center text-gray-50 max-w-[16ch] text-extrabold">{{ title }}</h3>
|
||||
<h3 class="text-center text-white text-xl md:text-base md:max-w-[16ch]">{{ title }}</h3>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<div{{ attributes }}>
|
||||
<div class="p-4 flex flex-row gap-6 bg-orange-500 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60 rounded-md">
|
||||
<div class="p-4 flex flex-col md:flex-row gap-6 bg-orange-500 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60 rounded-md">
|
||||
{% if poster != null and poster != "https://image.tmdb.org/t/p/w500" %}
|
||||
<img class="w-24 rounded-lg" src="{{ poster }}" />
|
||||
<img class="w-full md:w-24 rounded-lg" src="{{ poster }}" />
|
||||
{% else %}
|
||||
<div class="w-32 h-[144px] rounded-lg bg-gray-700 flex items-center justify-center">
|
||||
<div class="w-full md:w-32 h-[144px] rounded-lg bg-gray-700 flex items-center justify-center">
|
||||
<twig:ux:icon width="16" name="hugeicons:loading-01" />
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -12,11 +12,11 @@
|
||||
<h3 class="mb-4 text-xl font-medium leading-tight font-bold text-gray-50">
|
||||
{{ title }} - {{ year }}
|
||||
</h3>
|
||||
<p class="text-gray-50">
|
||||
<p class="hidden md:text-gray-50">
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
<a class="h-9 rounded-md py-1 px-2 bg-green-600 text-gray-50"
|
||||
<a class="h-9 rounded-md py-1 px-2 bg-green-600 text-gray-50 text-center"
|
||||
href="{{ path('app_search_result', {mediaType: mediaType, imdbId: imdbId}) }}"
|
||||
>choose</a>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,60 @@
|
||||
season: episode['season_number'],
|
||||
episode: episode['episode_number'],
|
||||
active: 'true',
|
||||
}) }}></div>
|
||||
}) }}
|
||||
>
|
||||
<div class="p-4 md:p-6 flex flex-col gap-6 bg-orange-500 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60 rounded-md">
|
||||
<div class="flex flex-col md:flex-row gap-4">
|
||||
{% if episode['poster'] != null %}
|
||||
<img class="w-full md:w-64 rounded-lg" src="{{ episode['poster'] }}" />
|
||||
{% else %}
|
||||
<div class="w-full md:w-64 min-w-64 sticky h-[144px] rounded-lg bg-gray-700 flex items-center justify-center">
|
||||
<twig:ux:icon width="32" name="hugeicons:loading-01" />
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex flex-col gap-4 grow">
|
||||
<h4 class="text-md font-bold">
|
||||
{{ episode['episode_number'] }}. {{ episode['name'] }}
|
||||
</h4>
|
||||
<p>{{ episode['overview']|truncate }}</p>
|
||||
<div>
|
||||
<button class="py-1 px-1.5 mr-1 grow-0 font-bold text-xs bg-green-600 rounded-lg hover:cursor-pointer hover:bg-green-700 text-white"
|
||||
{{ stimulus_action('tv-results', 'toggleList', 'click') }}
|
||||
>
|
||||
<span {{ stimulus_target('tv-results', 'count') }}>-</span> results
|
||||
</button>
|
||||
|
||||
<small class="py-1 px-1.5 mr-1 grow-0 font-bold bg-gray-700 rounded-lg font-normal text-white" title="Air date {{ episode['name'] }}">
|
||||
{{ episode['air_date']|date }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4 justify-between">
|
||||
<div class="flex flex-col items-center">
|
||||
<input type="checkbox"
|
||||
{{ stimulus_target('tv-results', 'episodeSelector') }}
|
||||
/>
|
||||
</div>
|
||||
<button class="flex flex-col items-end transition-transform duration-300 ease-in-out rotate-90"
|
||||
{{ stimulus_target('tv-results', 'toggleButton') }}
|
||||
{{ stimulus_action('tv-results', 'toggleList', 'click') }}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32">
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M20 6L10 16l10 10" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div {{ stimulus_target('tv-results', 'listContainer') }} class="inline-block overflow-hidden rounded-lg">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% set paginator = this.episodes %}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% block body %}
|
||||
<div class="p-4 flex flex-col grow gap-4 z-30">
|
||||
<h2 class="mb-2 text-3xl font-bold text-gray-50">Dashboard</h2>
|
||||
<div class="flex flex-row gap-4">
|
||||
<div class="flex flex-col md:flex-row gap-4">
|
||||
<twig:Card title="Active Downloads" class="w-full">
|
||||
<twig:DownloadList :type="'active'" />
|
||||
</twig:Card>
|
||||
@@ -14,13 +14,13 @@
|
||||
<twig:DownloadList :type="'complete'" />
|
||||
</twig:Card>
|
||||
</div>
|
||||
<div class="flex flex-row gap-4">
|
||||
<div class="flex flex-col md:flex-row gap-4">
|
||||
<twig:Card title="Monitors" class="w-full">
|
||||
<twig:MonitorList :type="'active'" :isWidget="true" />
|
||||
</twig:Card>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4">
|
||||
<twig:Card title="Popular Movies" contentClass="flex flex-row justify-between w-full">
|
||||
<twig:Card title="Popular Movies" contentClass="flex flex-col gap-4 md:flex-row md:justify-between w-full">
|
||||
{% for movie in popular_movies %}
|
||||
<twig:Poster imdbId="{{ movie.imdbId }}"
|
||||
tmdbId="{{ movie.tmdbId }}"
|
||||
@@ -32,7 +32,7 @@
|
||||
/>
|
||||
{% endfor %}
|
||||
</twig:Card>
|
||||
<twig:Card title="Popular TV Shows" contentClass="flex flex-row justify-between w-full">
|
||||
<twig:Card title="Popular TV Shows" contentClass="flex flex-col md:flex-row justify-between w-full">
|
||||
{% for movie in popular_tvshows %}
|
||||
<twig:Poster imdbId="{{ movie.imdbId }}"
|
||||
tmdbId="{{ movie.tmdbId }}"
|
||||
|
||||
@@ -15,11 +15,5 @@
|
||||
</twig:Card>
|
||||
</div>
|
||||
|
||||
<div class="p-2">
|
||||
<twig:Card title="Upcoming Episodes" >
|
||||
<twig:UpcomingEpisodes />
|
||||
</twig:Card>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
<h2 class="mb-2 text-3xl font-bold text-gray-50">Media Results</h2>
|
||||
<div class="flex flex-row w-full gap-2">
|
||||
<twig:Card title="" contentClass="flex flex-col gap-4 justify-between w-full text-gray-50">
|
||||
<div class="p-4 flex flex-row gap-6">
|
||||
<div class="p-2 md:p-4 flex flex-col md:flex-row gap-6">
|
||||
{% if results.media.poster != null %}
|
||||
<img class="w-40 rounded-lg" src="{{ results.media.poster }}" />
|
||||
<img class="w-full md:w-40 rounded-lg" src="{{ results.media.poster }}" />
|
||||
{% else %}
|
||||
<div class="w-40 h-[144px] rounded-lg bg-gray-700 flex items-center justify-center">
|
||||
<div class="w-full md:w-40 h-[144px] rounded-lg bg-gray-700 flex items-center justify-center">
|
||||
<twig:ux:icon width="24" name="hugeicons:loading-01" />
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -119,6 +119,7 @@
|
||||
</div>
|
||||
{% elseif "tvshows" == results.media.mediaType %}
|
||||
<twig:TvEpisodeList
|
||||
results="results"
|
||||
:imdbId="results.media.imdbId" :season="results.season" :perPage="20" :pageNumber="1"
|
||||
:tmdbId="results.media.tmdbId" :title="results.media.title" loading="defer"
|
||||
/>
|
||||
@@ -126,4 +127,20 @@
|
||||
</twig:Card>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
thead tr:not(:first-child) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
td:not(:last-child) {
|
||||
border-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,66 +1,70 @@
|
||||
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400 {{ results.media.mediaType == "tvshows" ? "hidden" }}"
|
||||
<table class="w-full max-w-[75vw] text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400 flex-row flex-no-wrap {{ results.media.mediaType == "tvshows" ? "hidden" : "options-table" }}"
|
||||
{{ stimulus_target(controller, "list") }}
|
||||
>
|
||||
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
|
||||
<tr class="dark:bg-stone-600 overflow-hidden">
|
||||
<thead class="text-xs text-gray-700 uppercase dark:text-gray-400">
|
||||
{% for result in results.results %}
|
||||
<tr class="dark:bg-stone-600 overflow-hidden flex flex-col md:flex-col flex-no wrap md:table-row border-b border-gray-500">
|
||||
<th scope="col"
|
||||
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
class="px-4 py-4 leading-[20px] font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
Size
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
class="px-4 py-4 leading-[20px] font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
Resolution
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
class="px-4 py-4 leading-[20px] font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
Codec
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
class="px-4 py-4 leading-[20px] font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
Seeders
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
class="px-4 py-4 leading-[20px] font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
Provider
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
class="px-4 py-4 leading-[20px] font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
Language
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
class="px-4 py-4 leading-[32px] font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="flex-1 sm:flex-none">
|
||||
{% for result in results.results %}
|
||||
<tr class="bg-white border-b dark:bg-slate-700 dark:border-gray-600 border-gray-200" data-provider="{{ result.provider }}" data-languages="{{ result.languages|json_encode }}" {% if "tvshows" == results.media.mediaType %} data-season="{{ results.season }} {% endif %}">
|
||||
<td id="size" class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50">
|
||||
<tr class="bg-white dark:bg-slate-700 flex flex-col flex-no wrap sm:table-row border-b border-gray-500" data-provider="{{ result.provider }}" data-languages="{{ result.languages|json_encode }}" {% if "tvshows" == results.media.mediaType %} data-season="{{ results.season }}"{% endif %}>
|
||||
<td id="size" class="px-4 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50">
|
||||
{{ result.size }}
|
||||
</td>
|
||||
<td id="resolution" class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50">
|
||||
<td id="resolution" class="px-4 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50">
|
||||
{{ result.resolution }}
|
||||
</td>
|
||||
<td id="codec" class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50">
|
||||
<td id="codec" class="px-4 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50">
|
||||
{{ result.codec }}
|
||||
</td>
|
||||
<td id="seeders" class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50">
|
||||
<td id="seeders" class="px-4 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50">
|
||||
{{ result.seeders }}
|
||||
</td>
|
||||
<td id="provider" class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50" data-provider="{{ result.provider }}">
|
||||
<td id="provider" class="px-4 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50 " data-provider="{{ result.provider }}">
|
||||
{{ result.provider }}
|
||||
</td>
|
||||
<td id="language" class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50" data-languages="{{ result.languages|json_encode }}">
|
||||
<td id="language" class="px-4 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50 overflow-scroll" data-languages="{{ result.languages|json_encode }}">
|
||||
{{ result.languageFlags|raw }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-end text-gray-800 dark:text-gray-50 flex flex-row gap-2 items-center justify-end">
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-end text-gray-800 dark:text-gray-50 flex flex-row gap-2 items-center justify-start mb:justify-end">
|
||||
<button class="download-btn p-1.5 bg-green-600 rounded-md text-gray-50"
|
||||
{{ stimulus_controller('download_button', {
|
||||
url: result.url,
|
||||
title: results.media.title,
|
||||
filename: result.filename,
|
||||
mediaType: results.media.mediaType,
|
||||
imdbId: results.media.imdbId
|
||||
imdbId: results.media.imdbId,
|
||||
episodeId: results|episode_id_from_results
|
||||
}) }}
|
||||
{{ stimulus_action('download_button', 'download', 'click') }}
|
||||
>
|
||||
|
||||
@@ -1,82 +1 @@
|
||||
<div class="p-6 flex flex-col gap-6 bg-orange-500 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60 rounded-md">
|
||||
<div class="flex flex-row gap-4">
|
||||
{% if results.media.poster != null %}
|
||||
<img class="w-64 rounded-lg" src="{{ results.media.poster }}" />
|
||||
{% else %}
|
||||
<div class="w-64 min-w-64 sticky h-[144px] rounded-lg bg-gray-700 flex items-center justify-center">
|
||||
<twig:ux:icon width="32" name="hugeicons:loading-01" />
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex flex-col gap-4 grow">
|
||||
<h4 class="text-md font-bold">
|
||||
{{ results.episode }}. {{ results.media.title }}
|
||||
</h4>
|
||||
<p>{{ results.media.description }}</p>
|
||||
<div>
|
||||
<button class="py-1 px-1.5 mr-1 grow-0 font-bold text-xs bg-green-600 rounded-lg hover:cursor-pointer hover:bg-green-700 text-white"
|
||||
{{ stimulus_action('tv-results', 'toggleList', 'click') }}
|
||||
>
|
||||
<span {{ stimulus_target('tv-results', 'count') }}>{{ results.results|length }}</span> results
|
||||
</button>
|
||||
|
||||
{% if results.file != false %}
|
||||
<span data-controller="popover">
|
||||
<template data-popover-target="content">
|
||||
<div data-popover-target="card" class="absolute z-40 p-1 bg-stone-400 p-1 text-black rounded-md m-1 animate-fade">
|
||||
<p class="font-bold text-sm text-left">Existing file(s) for this episode:</p>
|
||||
<ul class="list-disc ml-3">
|
||||
<li class="font-normal">{{ results.file.realPath|strip_media_path }} — <strong>{{ results.file.size|filesize }}</strong></li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
<small
|
||||
class="py-1 px-1.5 mr-1 grow-0 font-bold bg-blue-600 rounded-lg text-center text-white"
|
||||
data-action="mouseenter->popover#show mouseleave->popover#hide"
|
||||
>
|
||||
exists
|
||||
</small>
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
{% if results.file == false %}
|
||||
<small class="py-1 px-1.5 mr-1 grow-0 font-bold bg-rose-600 rounded-lg text-white" title="Episode has not been downloaded yet.">
|
||||
missing
|
||||
</small>
|
||||
{% endif %}
|
||||
|
||||
<small class="py-1 px-1.5 mr-1 grow-0 font-bold bg-gray-700 rounded-lg font-normal text-white" title="Air date {{ results.media.episodeAirDate }}">
|
||||
{{ results.media.episodeAirDate }}
|
||||
</small>
|
||||
{# <small class="py-1 px-1.5 grow-0 font-bold bg-red-600 hover:bg-red-700 rounded-lg font-normal text-white cursor-pointer" title="Clear cache for {{ results.media.title }}"#}
|
||||
{# {{ stimulus_action('tv-results', 'clearCache', 'click') }}#}
|
||||
{# >Clear Cache</small>#}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4 justify-between">
|
||||
<div class="flex flex-col items-center">
|
||||
<input type="checkbox"
|
||||
{{ stimulus_target('tv-results', 'episodeSelector') }}
|
||||
/>
|
||||
</div>
|
||||
<button class="flex flex-col items-end transition-transform duration-300 ease-in-out rotate-90"
|
||||
{{ stimulus_target('tv-results', 'toggleButton') }}
|
||||
{{ stimulus_action('tv-results', 'toggleList', 'click') }}>
|
||||
{# <svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" viewBox="0 0 32 32">#}
|
||||
{# <path fill="currentColor" d="m16 10l10 10l-1.4 1.4l-8.6-8.6l-8.6 8.6L6 20z"/>#}
|
||||
{# </svg>#}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32">
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M20 6L10 16l10 10" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-block overflow-hidden rounded-lg">
|
||||
{{ include('torrentio/partial/option-table.html.twig', {controller: 'tv-results'}) }}
|
||||
</div>
|
||||
</div>
|
||||
{{ include('torrentio/partial/option-table.html.twig', {controller: 'tv-results'}) }}
|
||||
|
||||
Reference in New Issue
Block a user