mirror of
https://code.castopod.org/adaures/castopod
synced 2025-04-19 13:01:19 +00:00
refactor(persons): move podcast and episode persons models to person model for consistency
- fix lazy loading properties + podcast import controller - rename all snake_case variables to camelCase - fix broken routes - refactor Location construction logic and setters
This commit is contained in:
parent
6b74a9e98a
commit
93e605b406
@ -164,13 +164,13 @@ $routes->group(
|
||||
]);
|
||||
|
||||
$routes->group('persons', function ($routes): void {
|
||||
$routes->get('/', 'PodcastPodcastController/$1', [
|
||||
$routes->get('/', 'PodcastPersonController/$1', [
|
||||
'as' => 'podcast-person-manage',
|
||||
'filter' => 'permission:podcast-edit',
|
||||
]);
|
||||
$routes->post(
|
||||
'/',
|
||||
'PodcastPodcastController::attemptAdd/$1',
|
||||
'PodcastPersonController::attemptAdd/$1',
|
||||
[
|
||||
'filter' => 'permission:podcast-edit',
|
||||
],
|
||||
@ -178,7 +178,7 @@ $routes->group(
|
||||
|
||||
$routes->get(
|
||||
'(:num)/remove',
|
||||
'PodcastPodcastController::remove/$1/$2',
|
||||
'PodcastPersonController::remove/$1/$2',
|
||||
[
|
||||
'as' => 'podcast-person-remove',
|
||||
'filter' => 'permission:podcast-edit',
|
||||
|
@ -12,6 +12,7 @@ use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use Config\Database;
|
||||
use App\Entities\Episode;
|
||||
use App\Entities\Location;
|
||||
use App\Entities\Note;
|
||||
use App\Entities\Podcast;
|
||||
use App\Models\EpisodeModel;
|
||||
@ -133,7 +134,9 @@ class EpisodeController extends BaseController
|
||||
'audio_file' => $this->request->getFile('audio_file'),
|
||||
'description_markdown' => $this->request->getPost('description'),
|
||||
'image' => $this->request->getFile('image'),
|
||||
'location' => $this->request->getPost('location_name'),
|
||||
'location' => new Location(
|
||||
$this->request->getPost('location_name'),
|
||||
),
|
||||
'transcript' => $this->request->getFile('transcript'),
|
||||
'chapters' => $this->request->getFile('chapters'),
|
||||
'parental_advisory' =>
|
||||
@ -249,7 +252,9 @@ class EpisodeController extends BaseController
|
||||
$this->episode->description_markdown = $this->request->getPost(
|
||||
'description',
|
||||
);
|
||||
$this->episode->location = $this->request->getPost('location_name');
|
||||
$this->episode->location = new Location(
|
||||
$this->request->getPost('location_name'),
|
||||
);
|
||||
$this->episode->parental_advisory =
|
||||
$this->request->getPost('parental_advisory') !== 'undefined'
|
||||
? $this->request->getPost('parental_advisory')
|
||||
@ -673,17 +678,17 @@ class EpisodeController extends BaseController
|
||||
|
||||
public function soundbitesAttemptEdit(): RedirectResponse
|
||||
{
|
||||
$soundbites_array = $this->request->getPost('soundbites_array');
|
||||
$soundbites = $this->request->getPost('soundbites');
|
||||
$rules = [
|
||||
'soundbites_array.0.start_time' =>
|
||||
'permit_empty|required_with[soundbites_array.0.duration]|decimal|greater_than_equal_to[0]',
|
||||
'soundbites_array.0.duration' =>
|
||||
'permit_empty|required_with[soundbites_array.0.start_time]|decimal|greater_than_equal_to[0]',
|
||||
'soundbites.0.start_time' =>
|
||||
'permit_empty|required_with[soundbites.0.duration]|decimal|greater_than_equal_to[0]',
|
||||
'soundbites.0.duration' =>
|
||||
'permit_empty|required_with[soundbites.0.start_time]|decimal|greater_than_equal_to[0]',
|
||||
];
|
||||
foreach (array_keys($soundbites_array) as $soundbite_id) {
|
||||
foreach (array_keys($soundbites) as $soundbite_id) {
|
||||
$rules += [
|
||||
"soundbites_array.{$soundbite_id}.start_time" => 'required|decimal|greater_than_equal_to[0]',
|
||||
"soundbites_array.{$soundbite_id}.duration" => 'required|decimal|greater_than_equal_to[0]',
|
||||
"soundbites.{$soundbite_id}.start_time" => 'required|decimal|greater_than_equal_to[0]',
|
||||
"soundbites.{$soundbite_id}.duration" => 'required|decimal|greater_than_equal_to[0]',
|
||||
];
|
||||
}
|
||||
if (!$this->validate($rules)) {
|
||||
@ -693,16 +698,13 @@ class EpisodeController extends BaseController
|
||||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
foreach ($soundbites_array as $soundbite_id => $soundbite) {
|
||||
if (
|
||||
$soundbite['start_time'] !== null &&
|
||||
$soundbite['duration'] !== null
|
||||
) {
|
||||
foreach ($soundbites as $soundbite_id => $soundbite) {
|
||||
if ((int) $soundbite['start_time'] < (int) $soundbite['duration']) {
|
||||
$data = [
|
||||
'podcast_id' => $this->podcast->id,
|
||||
'episode_id' => $this->episode->id,
|
||||
'start_time' => $soundbite['start_time'],
|
||||
'duration' => $soundbite['duration'],
|
||||
'start_time' => (int) $soundbite['start_time'],
|
||||
'duration' => (int) $soundbite['duration'],
|
||||
'label' => $soundbite['label'],
|
||||
'updated_by' => user_id(),
|
||||
];
|
||||
@ -711,6 +713,7 @@ class EpisodeController extends BaseController
|
||||
} else {
|
||||
$data += ['id' => $soundbite_id];
|
||||
}
|
||||
|
||||
$soundbiteModel = new SoundbiteModel();
|
||||
if (!$soundbiteModel->save($data)) {
|
||||
return redirect()
|
||||
|
@ -23,7 +23,7 @@ class EpisodePersonController extends BaseController
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
{
|
||||
if (count($params) <= 2) {
|
||||
if (count($params) < 2) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
@ -54,10 +54,6 @@ class EpisodePersonController extends BaseController
|
||||
$data = [
|
||||
'episode' => $this->episode,
|
||||
'podcast' => $this->podcast,
|
||||
'episodePersons' => (new PersonModel())->getEpisodePersons(
|
||||
$this->podcast->id,
|
||||
$this->episode->id,
|
||||
),
|
||||
'personOptions' => (new PersonModel())->getPersonOptions(),
|
||||
'taxonomyOptions' => (new PersonModel())->getTaxonomyOptions(),
|
||||
];
|
||||
@ -65,7 +61,7 @@ class EpisodePersonController extends BaseController
|
||||
0 => $this->podcast->title,
|
||||
1 => $this->episode->title,
|
||||
]);
|
||||
return view('admin/episode/person', $data);
|
||||
return view('admin/episode/persons', $data);
|
||||
}
|
||||
|
||||
public function attemptAdd(): RedirectResponse
|
||||
@ -91,12 +87,12 @@ class EpisodePersonController extends BaseController
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function remove(int $episodePersonId): RedirectResponse
|
||||
public function remove(int $personId): RedirectResponse
|
||||
{
|
||||
(new PersonModel())->removeEpisodePersons(
|
||||
(new PersonModel())->removePersonFromEpisode(
|
||||
$this->podcast->id,
|
||||
$this->episode->id,
|
||||
$episodePersonId,
|
||||
$personId,
|
||||
);
|
||||
|
||||
return redirect()->back();
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Entities\Image;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use App\Entities\Person;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
@ -77,7 +78,7 @@ class PersonController extends BaseController
|
||||
'full_name' => $this->request->getPost('full_name'),
|
||||
'unique_name' => $this->request->getPost('unique_name'),
|
||||
'information_url' => $this->request->getPost('information_url'),
|
||||
'image' => $this->request->getFile('image'),
|
||||
'image' => new Image($this->request->getFile('image')),
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
]);
|
||||
@ -125,9 +126,9 @@ class PersonController extends BaseController
|
||||
$this->person->information_url = $this->request->getPost(
|
||||
'information_url',
|
||||
);
|
||||
$image = $this->request->getFile('image');
|
||||
if ($image->isValid()) {
|
||||
$this->person->image = $image;
|
||||
$imageFile = $this->request->getFile('image');
|
||||
if ($imageFile !== null && $imageFile->isValid()) {
|
||||
$this->person->image = new Image($imageFile);
|
||||
}
|
||||
|
||||
$this->person->updated_by = user_id();
|
||||
|
@ -9,6 +9,7 @@
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Entities\Image;
|
||||
use App\Entities\Location;
|
||||
use App\Entities\Podcast;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use Config\Database;
|
||||
@ -170,7 +171,9 @@ class PodcastController extends BaseController
|
||||
'publisher' => $this->request->getPost('publisher'),
|
||||
'type' => $this->request->getPost('type'),
|
||||
'copyright' => $this->request->getPost('copyright'),
|
||||
'location' => $this->request->getPost('location_name'),
|
||||
'location' => new Location(
|
||||
$this->request->getPost('location_name'),
|
||||
),
|
||||
'payment_pointer' => $this->request->getPost('payment_pointer'),
|
||||
'custom_rss_string' => $this->request->getPost('custom_rss'),
|
||||
'partner_id' => $this->request->getPost('partner_id'),
|
||||
@ -271,7 +274,9 @@ class PodcastController extends BaseController
|
||||
$this->podcast->owner_email = $this->request->getPost('owner_email');
|
||||
$this->podcast->type = $this->request->getPost('type');
|
||||
$this->podcast->copyright = $this->request->getPost('copyright');
|
||||
$this->podcast->location = $this->request->getPost('location_name');
|
||||
$this->podcast->location = new Location(
|
||||
$this->request->getPost('location_name'),
|
||||
);
|
||||
$this->podcast->payment_pointer = $this->request->getPost(
|
||||
'payment_pointer',
|
||||
);
|
||||
|
@ -16,6 +16,7 @@ use Config\Database;
|
||||
use Podlibre\PodcastNamespace\ReversedTaxonomy;
|
||||
use App\Entities\Episode;
|
||||
use App\Entities\Image;
|
||||
use App\Entities\Location;
|
||||
use App\Entities\Person;
|
||||
use App\Models\CategoryModel;
|
||||
use App\Models\LanguageModel;
|
||||
@ -121,7 +122,7 @@ class PodcastImportController extends BaseController
|
||||
|
||||
try {
|
||||
if (
|
||||
$nsItunes->image !== null &&
|
||||
isset($nsItunes->image) &&
|
||||
$nsItunes->image->attributes()['href'] !== null
|
||||
) {
|
||||
$imageFile = download_file(
|
||||
@ -133,6 +134,15 @@ class PodcastImportController extends BaseController
|
||||
);
|
||||
}
|
||||
|
||||
$location = null;
|
||||
if (isset($nsPodcast->location)) {
|
||||
$location = new Location(
|
||||
(string) $nsPodcast->location,
|
||||
(string) $nsPodcast->location->attributes()['geo'],
|
||||
(string) $nsPodcast->location->attributes()['osm'],
|
||||
);
|
||||
}
|
||||
|
||||
$podcast = new Podcast([
|
||||
'name' => $this->request->getPost('name'),
|
||||
'imported_feed_url' => $this->request->getPost(
|
||||
@ -150,40 +160,27 @@ class PodcastImportController extends BaseController
|
||||
'language_code' => $this->request->getPost('language'),
|
||||
'category_id' => $this->request->getPost('category'),
|
||||
'parental_advisory' =>
|
||||
$nsItunes->explicit === null
|
||||
? null
|
||||
: (in_array($nsItunes->explicit, ['yes', 'true'])
|
||||
isset($nsItunes->explicit)
|
||||
? (in_array((string) $nsItunes->explicit, ['yes', 'true'])
|
||||
? 'explicit'
|
||||
: (in_array($nsItunes->explicit, ['no', 'false'])
|
||||
: (in_array((string) $nsItunes->explicit, ['no', 'false'])
|
||||
? 'clean'
|
||||
: null)),
|
||||
: null))
|
||||
: null,
|
||||
'owner_name' => (string) $nsItunes->owner->name,
|
||||
'owner_email' => (string) $nsItunes->owner->email,
|
||||
'publisher' => (string) $nsItunes->author,
|
||||
'type' =>
|
||||
$nsItunes->type === null ? 'episodic' : $nsItunes->type,
|
||||
'type' => isset($nsItunes->type) ? (string) $nsItunes->type : 'episodic',
|
||||
'copyright' => (string) $feed->channel[0]->copyright,
|
||||
'is_blocked' =>
|
||||
$nsItunes->block === null
|
||||
? false
|
||||
: $nsItunes->block === 'yes',
|
||||
isset($nsItunes->block)
|
||||
? (string) $nsItunes->block === 'yes'
|
||||
: false,
|
||||
'is_completed' =>
|
||||
$nsItunes->complete === null
|
||||
? false
|
||||
: $nsItunes->complete === 'yes',
|
||||
'location_name' => $nsPodcast->location
|
||||
? (string) $nsPodcast->location
|
||||
: null,
|
||||
'location_geo' =>
|
||||
!$nsPodcast->location ||
|
||||
$nsPodcast->location->attributes()['geo'] === null
|
||||
? null
|
||||
: (string) $nsPodcast->location->attributes()['geo'],
|
||||
'location_osm_id' =>
|
||||
!$nsPodcast->location ||
|
||||
$nsPodcast->location->attributes()['osm'] === null
|
||||
? null
|
||||
: (string) $nsPodcast->location->attributes()['osm'],
|
||||
isset($nsItunes->complete)
|
||||
? (string) $nsItunes->complete === 'yes'
|
||||
: false,
|
||||
'location' => $location,
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
]);
|
||||
@ -277,18 +274,17 @@ class PodcastImportController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
$personGroup =
|
||||
isset($podcastPerson->attributes()['group'])
|
||||
? ['slug' => '']
|
||||
: ReversedTaxonomy::$taxonomy[(string) $podcastPerson->attributes()['group']];
|
||||
$personRole =
|
||||
isset($podcastPerson->attributes()['role']) ||
|
||||
$personGroup === null
|
||||
? ['slug' => '']
|
||||
: $personGroup['roles'][strval($podcastPerson->attributes()['role'])];
|
||||
// TODO: these checks should be in the taxonomy as default values
|
||||
$podcastPersonGroup = $podcastPerson->attributes()['group'] ?? "Cast";
|
||||
$podcastPersonRole = $podcastPerson->attributes()['role'] ?? "Host";
|
||||
|
||||
$personGroup = ReversedTaxonomy::$taxonomy[(string) $podcastPersonGroup];
|
||||
|
||||
$personGroupSlug = $personGroup['slug'];
|
||||
$personRoleSlug = $personGroup['roles'][(string) $podcastPersonRole]['slug'];
|
||||
|
||||
$podcastPersonModel = new PersonModel();
|
||||
if (!$podcastPersonModel->addPodcastPerson($newPodcastId, $newPersonId, $personGroup['slug'], $personRole['slug'])) {
|
||||
if (!$podcastPersonModel->addPodcastPerson($newPodcastId, $newPersonId, $personGroupSlug, $personRoleSlug)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
@ -341,7 +337,7 @@ class PodcastImportController extends BaseController
|
||||
};
|
||||
|
||||
if (
|
||||
$nsItunes->image !== null &&
|
||||
isset($nsItunes->image) &&
|
||||
$nsItunes->image->attributes()['href'] !== null
|
||||
) {
|
||||
$episodeImage = new Image(
|
||||
@ -353,6 +349,15 @@ class PodcastImportController extends BaseController
|
||||
$episodeImage = null;
|
||||
}
|
||||
|
||||
$location = null;
|
||||
if (isset($nsPodcast->location)) {
|
||||
$location = new Location(
|
||||
(string) $nsPodcast->location,
|
||||
(string) $nsPodcast->location->attributes()['geo'],
|
||||
(string) $nsPodcast->location->attributes()['osm'],
|
||||
);
|
||||
}
|
||||
|
||||
$newEpisode = new Episode([
|
||||
'podcast_id' => $newPodcastId,
|
||||
'guid' => $item->guid ?? null,
|
||||
@ -367,13 +372,13 @@ class PodcastImportController extends BaseController
|
||||
'description_html' => $itemDescriptionHtml,
|
||||
'image' => $episodeImage,
|
||||
'parental_advisory' =>
|
||||
$nsItunes->explicit === null
|
||||
? null
|
||||
: (in_array($nsItunes->explicit, ['yes', 'true'])
|
||||
isset($nsItunes->explicit)
|
||||
? (in_array((string) $nsItunes->explicit, ['yes', 'true'])
|
||||
? 'explicit'
|
||||
: (in_array($nsItunes->explicit, ['no', 'false'])
|
||||
: (in_array((string) $nsItunes->explicit, ['no', 'false'])
|
||||
? 'clean'
|
||||
: null)),
|
||||
: null))
|
||||
: null,
|
||||
'number' =>
|
||||
$this->request->getPost('force_renumber') === 'yes'
|
||||
? $itemNumber
|
||||
@ -382,27 +387,13 @@ class PodcastImportController extends BaseController
|
||||
$this->request->getPost('season_number') === null
|
||||
? $nsItunes->season
|
||||
: $this->request->getPost('season_number'),
|
||||
'type' =>
|
||||
$nsItunes->episodeType === null
|
||||
? 'full'
|
||||
: $nsItunes->episodeType,
|
||||
'is_blocked' =>
|
||||
$nsItunes->block === null
|
||||
? false
|
||||
: $nsItunes->block === 'yes',
|
||||
'location_name' => $nsPodcast->location
|
||||
? $nsPodcast->location
|
||||
: null,
|
||||
'location_geo' =>
|
||||
!$nsPodcast->location ||
|
||||
$nsPodcast->location->attributes()['geo'] === null
|
||||
? null
|
||||
: $nsPodcast->location->attributes()['geo'],
|
||||
'location_osm_id' =>
|
||||
!$nsPodcast->location ||
|
||||
$nsPodcast->location->attributes()['osm'] === null
|
||||
? null
|
||||
: $nsPodcast->location->attributes()['osm'],
|
||||
'type' => isset($nsItunes->episodeType)
|
||||
? (string) $nsItunes->episodeType
|
||||
: 'full',
|
||||
'is_blocked' => isset($nsItunes->block)
|
||||
? (string) $nsItunes->block === 'yes'
|
||||
: false,
|
||||
'location' => $location,
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
'published_at' => strtotime($item->pubDate),
|
||||
@ -425,14 +416,16 @@ class PodcastImportController extends BaseController
|
||||
if (($newPerson = $personModel->getPerson($fullName)) !== null) {
|
||||
$newPersonId = $newPerson->id;
|
||||
} else {
|
||||
$newEpisodePerson = new Person([
|
||||
$newPerson = new Person([
|
||||
'full_name' => $fullName,
|
||||
'slug' => slugify($fullName),
|
||||
'unique_name' => slugify($fullName),
|
||||
'information_url' => $episodePerson->attributes()['href'],
|
||||
'image' => new Image(download_file($episodePerson->attributes()['img']))
|
||||
'image' => new Image(download_file($episodePerson->attributes()['img'])),
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
]);
|
||||
|
||||
if (!($newPersonId = $personModel->insert($newEpisodePerson))) {
|
||||
if (!($newPersonId = $personModel->insert($newPerson))) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
@ -440,19 +433,17 @@ class PodcastImportController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
$personGroup =
|
||||
$episodePerson->attributes()['group'] === null
|
||||
? ['slug' => '']
|
||||
: ReversedTaxonomy::$taxonomy[strval($episodePerson->attributes()['group'])];
|
||||
$personRole =
|
||||
$episodePerson->attributes()['role'] === null ||
|
||||
$personGroup === null
|
||||
? ['slug' => '']
|
||||
: $personGroup['roles'][strval($episodePerson->attributes()['role'])];
|
||||
// TODO: these checks should be in the taxonomy as default values
|
||||
$episodePersonGroup = $episodePerson->attributes()['group'] ?? "Cast";
|
||||
$episodePersonRole = $episodePerson->attributes()['role'] ?? "Host";
|
||||
|
||||
$personGroup = ReversedTaxonomy::$taxonomy[(string) $episodePersonGroup];
|
||||
|
||||
$personGroupSlug = $personGroup['slug'];
|
||||
$personRoleSlug = $personGroup['roles'][(string) $episodePersonRole]['slug'];
|
||||
|
||||
$episodePersonModel = new PersonModel();
|
||||
if (!$episodePersonModel->addEpisodePerson($newPodcastId, $newEpisodeId, $newPersonId, $personGroup['slug'], $personRole['slug'])) {
|
||||
if (!$episodePersonModel->addEpisodePerson($newPodcastId, $newEpisodeId, $newPersonId, $personGroupSlug, $personRoleSlug)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
@ -54,13 +54,13 @@ class PodcastPersonController extends BaseController
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/podcast/person', $data);
|
||||
return view('admin/podcast/persons', $data);
|
||||
}
|
||||
|
||||
public function attemptAdd(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'person' => 'required',
|
||||
'persons' => 'required',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
@ -72,18 +72,18 @@ class PodcastPersonController extends BaseController
|
||||
|
||||
(new PersonModel())->addPodcastPersons(
|
||||
$this->podcast->id,
|
||||
$this->request->getPost('person'),
|
||||
$this->request->getPost('person_group_role'),
|
||||
$this->request->getPost('persons'),
|
||||
$this->request->getPost('roles') ?? [],
|
||||
);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function remove(int $podcastPersonId): RedirectResponse
|
||||
public function remove(int $personId): RedirectResponse
|
||||
{
|
||||
(new PersonModel())->removePodcastPersons(
|
||||
(new PersonModel())->removePersonFromPodcast(
|
||||
$this->podcast->id,
|
||||
$podcastPersonId,
|
||||
$personId,
|
||||
);
|
||||
|
||||
return redirect()->back();
|
||||
|
@ -69,26 +69,26 @@ class PageController extends BaseController
|
||||
$allCredits = (new CreditModel())->findAll();
|
||||
|
||||
// Unlike the carpenter, we make a tree from a table:
|
||||
$person_group = null;
|
||||
$person_id = null;
|
||||
$person_role = null;
|
||||
$personGroup = null;
|
||||
$personId = null;
|
||||
$personRole = null;
|
||||
$credits = [];
|
||||
foreach ($allCredits as $credit) {
|
||||
if ($person_group !== $credit->person_group) {
|
||||
$person_group = $credit->person_group;
|
||||
$person_id = $credit->person_id;
|
||||
$person_role = $credit->person_role;
|
||||
$credits[$person_group] = [
|
||||
if ($personGroup !== $credit->person_group) {
|
||||
$personGroup = $credit->person_group;
|
||||
$personId = $credit->person_id;
|
||||
$personRole = $credit->person_role;
|
||||
$credits[$personGroup] = [
|
||||
'group_label' => $credit->group_label,
|
||||
'persons' => [
|
||||
$person_id => [
|
||||
$personId => [
|
||||
'full_name' => $credit->person->full_name,
|
||||
'thumbnail_url' =>
|
||||
$credit->person->image->thumbnail_url,
|
||||
'information_url' =>
|
||||
$credit->person->information_url,
|
||||
'roles' => [
|
||||
$person_role => [
|
||||
$personRole => [
|
||||
'role_label' => $credit->role_label,
|
||||
'is_in' => [
|
||||
[
|
||||
@ -97,7 +97,7 @@ class PageController extends BaseController
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} ▸ "
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode
|
||||
->title .
|
||||
@ -117,16 +117,16 @@ class PageController extends BaseController
|
||||
],
|
||||
],
|
||||
];
|
||||
} elseif ($person_id !== $credit->person_id) {
|
||||
$person_id = $credit->person_id;
|
||||
$person_role = $credit->person_role;
|
||||
$credits[$person_group]['persons'][$person_id] = [
|
||||
} elseif ($personId !== $credit->person_id) {
|
||||
$personId = $credit->person_id;
|
||||
$personRole = $credit->person_role;
|
||||
$credits[$personGroup]['persons'][$personId] = [
|
||||
'full_name' => $credit->person->full_name,
|
||||
'thumbnail_url' =>
|
||||
$credit->person->image->thumbnail_url,
|
||||
'information_url' => $credit->person->information_url,
|
||||
'roles' => [
|
||||
$person_role => [
|
||||
$personRole => [
|
||||
'role_label' => $credit->role_label,
|
||||
'is_in' => [
|
||||
[
|
||||
@ -135,7 +135,7 @@ class PageController extends BaseController
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} ▸ "
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode->title .
|
||||
episode_numbering(
|
||||
@ -151,10 +151,10 @@ class PageController extends BaseController
|
||||
],
|
||||
],
|
||||
];
|
||||
} elseif ($person_role !== $credit->person_role) {
|
||||
$person_role = $credit->person_role;
|
||||
$credits[$person_group]['persons'][$person_id]['roles'][
|
||||
$person_role
|
||||
} elseif ($personRole !== $credit->person_role) {
|
||||
$personRole = $credit->person_role;
|
||||
$credits[$personGroup]['persons'][$personId]['roles'][
|
||||
$personRole
|
||||
] = [
|
||||
'role_label' => $credit->role_label,
|
||||
'is_in' => [
|
||||
@ -164,7 +164,7 @@ class PageController extends BaseController
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} ▸ "
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode->title .
|
||||
episode_numbering(
|
||||
@ -178,15 +178,15 @@ class PageController extends BaseController
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$credits[$person_group]['persons'][$person_id]['roles'][
|
||||
$person_role
|
||||
$credits[$personGroup]['persons'][$personId]['roles'][
|
||||
$personRole
|
||||
]['is_in'][] = [
|
||||
'link' => $credit->episode_id
|
||||
? $credit->episode->link
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} ▸ "
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode->title .
|
||||
episode_numbering(
|
||||
|
@ -142,7 +142,7 @@ class AddPodcasts extends Migration
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
],
|
||||
'location_osm_id' => [
|
||||
'location_osm' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 12,
|
||||
'null' => true,
|
||||
|
@ -137,7 +137,7 @@ class AddEpisodes extends Migration
|
||||
'constraint' => 32,
|
||||
'null' => true,
|
||||
],
|
||||
'location_osm_id' => [
|
||||
'location_osm' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 12,
|
||||
'null' => true,
|
||||
|
@ -35,7 +35,8 @@ class AddSoundbites extends Migration
|
||||
'type' => 'DECIMAL(8,3)',
|
||||
],
|
||||
'duration' => [
|
||||
'type' => 'DECIMAL(8,3)',
|
||||
// soundbite duration cannot be higher than 9999,999 seconds ~ 2.77 hours
|
||||
'type' => 'DECIMAL(7,3)',
|
||||
],
|
||||
'label' => [
|
||||
'type' => 'VARCHAR',
|
||||
|
@ -44,7 +44,7 @@ class AddEpisodesPersons extends Migration
|
||||
'constraint' => 32,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addPrimaryKey('id', true);
|
||||
$this->forge->addUniqueKey([
|
||||
'podcast_id',
|
||||
'episode_id',
|
||||
|
@ -52,12 +52,12 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
||||
$date < strtotime('now');
|
||||
$date = strtotime(date('Y-m-d', $date) . ' +1 day')
|
||||
) {
|
||||
$analytics_podcasts = [];
|
||||
$analytics_podcasts_by_hour = [];
|
||||
$analytics_podcasts_by_country = [];
|
||||
$analytics_podcasts_by_episode = [];
|
||||
$analytics_podcasts_by_player = [];
|
||||
$analytics_podcasts_by_region = [];
|
||||
$analyticsPodcasts = [];
|
||||
$analyticsPodcastsByHour = [];
|
||||
$analyticsPodcastsByCountry = [];
|
||||
$analyticsPodcastsByEpisode = [];
|
||||
$analyticsPodcastsByPlayer = [];
|
||||
$analyticsPodcastsByRegion = [];
|
||||
|
||||
$episodes = (new EpisodeModel())
|
||||
->where([
|
||||
@ -72,9 +72,9 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
||||
$probability1 = (int) floor(exp(3 - $age / 40)) + 1;
|
||||
|
||||
for (
|
||||
$num_line = 0;
|
||||
$num_line < rand(1, $probability1);
|
||||
++$num_line
|
||||
$lineNumber = 0;
|
||||
$lineNumber < rand(1, $probability1);
|
||||
++$lineNumber
|
||||
) {
|
||||
$probability2 = (int) floor(exp(6 - $age / 20)) + 10;
|
||||
|
||||
@ -129,7 +129,7 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
||||
|
||||
$hits = rand(0, $probability2);
|
||||
|
||||
$analytics_podcasts[] = [
|
||||
$analyticsPodcasts[] = [
|
||||
'podcast_id' => $podcast->id,
|
||||
'date' => date('Y-m-d', $date),
|
||||
'duration' => rand(60, 3600),
|
||||
@ -137,26 +137,26 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
||||
'hits' => $hits,
|
||||
'unique_listeners' => $hits,
|
||||
];
|
||||
$analytics_podcasts_by_hour[] = [
|
||||
$analyticsPodcastsByHour[] = [
|
||||
'podcast_id' => $podcast->id,
|
||||
'date' => date('Y-m-d', $date),
|
||||
'hour' => rand(0, 23),
|
||||
'hits' => $hits,
|
||||
];
|
||||
$analytics_podcasts_by_country[] = [
|
||||
$analyticsPodcastsByCountry[] = [
|
||||
'podcast_id' => $podcast->id,
|
||||
'date' => date('Y-m-d', $date),
|
||||
'country_code' => $countryCode,
|
||||
'hits' => $hits,
|
||||
];
|
||||
$analytics_podcasts_by_episode[] = [
|
||||
$analyticsPodcastsByEpisode[] = [
|
||||
'podcast_id' => $podcast->id,
|
||||
'date' => date('Y-m-d', $date),
|
||||
'episode_id' => $episode->id,
|
||||
'age' => $age,
|
||||
'hits' => $hits,
|
||||
];
|
||||
$analytics_podcasts_by_player[] = [
|
||||
$analyticsPodcastsByPlayer[] = [
|
||||
'podcast_id' => $podcast->id,
|
||||
'date' => date('Y-m-d', $date),
|
||||
'service' => $service,
|
||||
@ -166,7 +166,7 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
||||
'is_bot' => $isBot,
|
||||
'hits' => $hits,
|
||||
];
|
||||
$analytics_podcasts_by_region[] = [
|
||||
$analyticsPodcastsByRegion[] = [
|
||||
'podcast_id' => $podcast->id,
|
||||
'date' => date('Y-m-d', $date),
|
||||
'country_code' => $countryCode,
|
||||
@ -180,27 +180,27 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
||||
$this->db
|
||||
->table('analytics_podcasts')
|
||||
->ignore(true)
|
||||
->insertBatch($analytics_podcasts);
|
||||
->insertBatch($analyticsPodcasts);
|
||||
$this->db
|
||||
->table('analytics_podcasts_by_hour')
|
||||
->ignore(true)
|
||||
->insertBatch($analytics_podcasts_by_hour);
|
||||
->insertBatch($analyticsPodcastsByHour);
|
||||
$this->db
|
||||
->table('analytics_podcasts_by_country')
|
||||
->ignore(true)
|
||||
->insertBatch($analytics_podcasts_by_country);
|
||||
->insertBatch($analyticsPodcastsByCountry);
|
||||
$this->db
|
||||
->table('analytics_podcasts_by_episode')
|
||||
->ignore(true)
|
||||
->insertBatch($analytics_podcasts_by_episode);
|
||||
->insertBatch($analyticsPodcastsByEpisode);
|
||||
$this->db
|
||||
->table('analytics_podcasts_by_player')
|
||||
->ignore(true)
|
||||
->insertBatch($analytics_podcasts_by_player);
|
||||
->insertBatch($analyticsPodcastsByPlayer);
|
||||
$this->db
|
||||
->table('analytics_podcasts_by_region')
|
||||
->ignore(true)
|
||||
->insertBatch($analytics_podcasts_by_region);
|
||||
->insertBatch($analyticsPodcastsByRegion);
|
||||
}
|
||||
} else {
|
||||
echo "COULD NOT POPULATE DATABASE:\n\tCreate a podcast with episodes first.\n";
|
||||
|
@ -192,9 +192,9 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
|
||||
$date < strtotime('now');
|
||||
$date = strtotime(date('Y-m-d', $date) . ' +1 day')
|
||||
) {
|
||||
$website_by_browser = [];
|
||||
$website_by_entry_page = [];
|
||||
$website_by_referer = [];
|
||||
$websiteByBrowser = [];
|
||||
$websiteByEntryPage = [];
|
||||
$websiteByReferer = [];
|
||||
|
||||
$episodes = (new EpisodeModel())
|
||||
->where([
|
||||
@ -209,9 +209,9 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
|
||||
$probability1 = (int) floor(exp(3 - $age / 40)) + 1;
|
||||
|
||||
for (
|
||||
$num_line = 0;
|
||||
$num_line < rand(1, $probability1);
|
||||
++$num_line
|
||||
$lineNumber = 0;
|
||||
$lineNumber < rand(1, $probability1);
|
||||
++$lineNumber
|
||||
) {
|
||||
$probability2 = (int) floor(exp(6 - $age / 20)) + 10;
|
||||
|
||||
@ -228,19 +228,19 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
|
||||
|
||||
$hits = rand(0, $probability2);
|
||||
|
||||
$website_by_browser[] = [
|
||||
$websiteByBrowser[] = [
|
||||
'podcast_id' => $podcast->id,
|
||||
'date' => date('Y-m-d', $date),
|
||||
'browser' => $browser,
|
||||
'hits' => $hits,
|
||||
];
|
||||
$website_by_entry_page[] = [
|
||||
$websiteByEntryPage[] = [
|
||||
'podcast_id' => $podcast->id,
|
||||
'date' => date('Y-m-d', $date),
|
||||
'entry_page_url' => $episode->link,
|
||||
'hits' => $hits,
|
||||
];
|
||||
$website_by_referer[] = [
|
||||
$websiteByReferer[] = [
|
||||
'podcast_id' => $podcast->id,
|
||||
'date' => date('Y-m-d', $date),
|
||||
'referer_url' =>
|
||||
@ -254,15 +254,15 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
|
||||
$this->db
|
||||
->table('analytics_website_by_browser')
|
||||
->ignore(true)
|
||||
->insertBatch($website_by_browser);
|
||||
->insertBatch($websiteByBrowser);
|
||||
$this->db
|
||||
->table('analytics_website_by_entry_page')
|
||||
->ignore(true)
|
||||
->insertBatch($website_by_entry_page);
|
||||
->insertBatch($websiteByEntryPage);
|
||||
$this->db
|
||||
->table('analytics_website_by_referer')
|
||||
->ignore(true)
|
||||
->insertBatch($website_by_referer);
|
||||
->insertBatch($websiteByReferer);
|
||||
}
|
||||
} else {
|
||||
echo "COULD NOT POPULATE DATABASE:\n\tCreate a podcast with episodes first.\n";
|
||||
|
@ -18,7 +18,7 @@ use RuntimeException;
|
||||
*/
|
||||
class Actor extends ActivityPubActor
|
||||
{
|
||||
protected ?Podcast $podcast;
|
||||
protected ?Podcast $podcast = null;
|
||||
protected bool $is_podcast;
|
||||
|
||||
public function getIsPodcast(): bool
|
||||
|
@ -21,7 +21,7 @@ use CodeIgniter\Entity\Entity;
|
||||
*/
|
||||
class Category extends Entity
|
||||
{
|
||||
protected ?Category $parent;
|
||||
protected ?Category $parent = null;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
|
@ -29,9 +29,9 @@ use CodeIgniter\Entity\Entity;
|
||||
*/
|
||||
class Credit extends Entity
|
||||
{
|
||||
protected ?Person $person;
|
||||
protected ?Podcast $podcast;
|
||||
protected ?Episode $episode;
|
||||
protected ?Person $person = null;
|
||||
protected ?Podcast $podcast = null;
|
||||
protected ?Episode $episode = null;
|
||||
protected string $group_label;
|
||||
protected string $role_label;
|
||||
|
||||
|
@ -58,10 +58,10 @@ use RuntimeException;
|
||||
* @property int $season_number
|
||||
* @property string $type
|
||||
* @property bool $is_blocked
|
||||
* @property Location $location
|
||||
* @property Location|null $location
|
||||
* @property string|null $location_name
|
||||
* @property string|null $location_geo
|
||||
* @property string|null $location_osm_id
|
||||
* @property string|null $location_osm
|
||||
* @property array|null $custom_rss
|
||||
* @property string $custom_rss_string
|
||||
* @property int $favourites_total
|
||||
@ -90,7 +90,7 @@ class Episode extends Entity
|
||||
protected string $audio_file_opengraph_url;
|
||||
protected string $embeddable_player_url;
|
||||
protected Image $image;
|
||||
protected ?string $description;
|
||||
protected ?string $description = null;
|
||||
protected File $transcript_file;
|
||||
protected File $chapters_file;
|
||||
|
||||
@ -109,9 +109,9 @@ class Episode extends Entity
|
||||
*/
|
||||
protected $notes = [];
|
||||
|
||||
protected ?Location $location;
|
||||
protected ?Location $location = null;
|
||||
protected string $custom_rss_string;
|
||||
protected string $publication_status;
|
||||
protected ?string $publication_status = null;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
@ -152,7 +152,7 @@ class Episode extends Entity
|
||||
'is_blocked' => 'boolean',
|
||||
'location_name' => '?string',
|
||||
'location_geo' => '?string',
|
||||
'location_osm_id' => '?string',
|
||||
'location_osm' => '?string',
|
||||
'custom_rss' => '?json-array',
|
||||
'favourites_total' => 'integer',
|
||||
'reblogs_total' => 'integer',
|
||||
@ -202,7 +202,7 @@ class Episode extends Entity
|
||||
{
|
||||
helper(['media', 'id3']);
|
||||
|
||||
$audio_metadata = get_file_tags($audioFile);
|
||||
$audioMetadata = get_file_tags($audioFile);
|
||||
|
||||
$this->attributes['audio_file_path'] = save_media(
|
||||
$audioFile,
|
||||
@ -210,11 +210,11 @@ class Episode extends Entity
|
||||
$this->attributes['slug'],
|
||||
);
|
||||
$this->attributes['audio_file_duration'] =
|
||||
$audio_metadata['playtime_seconds'];
|
||||
$this->attributes['audio_file_mimetype'] = $audio_metadata['mime_type'];
|
||||
$this->attributes['audio_file_size'] = $audio_metadata['filesize'];
|
||||
$audioMetadata['playtime_seconds'];
|
||||
$this->attributes['audio_file_mimetype'] = $audioMetadata['mime_type'];
|
||||
$this->attributes['audio_file_size'] = $audioMetadata['filesize'];
|
||||
$this->attributes['audio_file_header_size'] =
|
||||
$audio_metadata['avdataoffset'];
|
||||
$audioMetadata['avdataoffset'];
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -471,10 +471,8 @@ class Episode extends Entity
|
||||
$this->getPodcast()->partner_link_url !== null &&
|
||||
$this->getPodcast()->partner_image_url !== null
|
||||
) {
|
||||
$descriptionHtml .= "<div><a href=\"{$this->getPartnerLink(
|
||||
$serviceSlug,
|
||||
)}\" rel=\"sponsored noopener noreferrer\" target=\"_blank\"><img src=\"{$this->getPartnerImageUrl(
|
||||
$serviceSlug,
|
||||
$descriptionHtml .= "<div><a href=\"{$this->getPartnerLink($serviceSlug,
|
||||
)}\" rel=\"sponsored noopener noreferrer\" target=\"_blank\"><img src=\"{$this->getPartnerImageUrl($serviceSlug,
|
||||
)}\" alt=\"Partner image\" /></a></div>";
|
||||
}
|
||||
|
||||
@ -504,47 +502,41 @@ class Episode extends Entity
|
||||
|
||||
public function getPublicationStatus(): string
|
||||
{
|
||||
if ($this->publication_status !== '') {
|
||||
return $this->publication_status;
|
||||
if ($this->publication_status === null) {
|
||||
if ($this->published_at === null) {
|
||||
$this->publication_status = 'not_published';
|
||||
} elseif ($this->published_at->isBefore(Time::now())) {
|
||||
$this->publication_status = 'published';
|
||||
} else {
|
||||
$this->publication_status = 'scheduled';
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->published_at === null) {
|
||||
return 'not_published';
|
||||
}
|
||||
|
||||
helper('date');
|
||||
if ($this->published_at->isBefore(Time::now())) {
|
||||
return 'published';
|
||||
}
|
||||
|
||||
return 'scheduled';
|
||||
return $this->publication_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the location name and fetches OpenStreetMap info
|
||||
*/
|
||||
public function setLocation(?string $newLocationName = null): static
|
||||
public function setLocation(?Location $location = null): static
|
||||
{
|
||||
if ($newLocationName === null) {
|
||||
if ($location === null) {
|
||||
$this->attributes['location_name'] = null;
|
||||
$this->attributes['location_geo'] = null;
|
||||
$this->attributes['location_osm_id'] = null;
|
||||
$this->attributes['location_osm'] = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
helper('location');
|
||||
|
||||
$oldLocationName = $this->attributes['location_name'];
|
||||
|
||||
if (
|
||||
$oldLocationName === null ||
|
||||
$oldLocationName !== $newLocationName
|
||||
!isset($this->attributes['location_name']) ||
|
||||
$this->attributes['location_name'] !== $location->name
|
||||
) {
|
||||
$this->attributes['location_name'] = $newLocationName;
|
||||
$location->fetchOsmLocation();
|
||||
|
||||
if ($location = fetch_osm_location($newLocationName)) {
|
||||
$this->attributes['location_geo'] = $location['geo'];
|
||||
$this->attributes['location_osm_id'] = $location['osm_id'];
|
||||
}
|
||||
$this->attributes['location_name'] = $location->name;
|
||||
$this->attributes['location_geo'] = $location->geo;
|
||||
$this->attributes['location_osm'] = $location->osm;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -557,11 +549,11 @@ class Episode extends Entity
|
||||
}
|
||||
|
||||
if ($this->location === null) {
|
||||
$this->location = new Location([
|
||||
'name' => $this->location_name,
|
||||
'geo' => $this->location_geo,
|
||||
'osm_id' => $this->location_osm_id,
|
||||
]);
|
||||
$this->location = new Location(
|
||||
$this->location_name,
|
||||
$this->location_geo,
|
||||
$this->location_osm,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->location;
|
||||
@ -645,9 +637,9 @@ class Episode extends Entity
|
||||
}
|
||||
|
||||
return rtrim($this->getPodcast()->partner_image_url, '/') .
|
||||
'?pid=' .
|
||||
$this->getPodcast()->partner_id .
|
||||
'&guid=' .
|
||||
urlencode($this->attributes['guid']);
|
||||
'?pid=' .
|
||||
$this->getPodcast()->partner_id .
|
||||
'&guid=' .
|
||||
urlencode($this->attributes['guid']);
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ use RuntimeException;
|
||||
class Image extends Entity
|
||||
{
|
||||
protected Images $config;
|
||||
protected ?File $file;
|
||||
protected ?File $file = null;
|
||||
protected string $dirname;
|
||||
protected string $filename;
|
||||
protected string $extension;
|
||||
|
@ -9,12 +9,13 @@
|
||||
namespace App\Entities;
|
||||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use Config\Services;
|
||||
|
||||
/**
|
||||
* @property string $url
|
||||
* @property string $name
|
||||
* @property string|null $geo
|
||||
* @property string|null $osm_id
|
||||
* @property string|null $osm
|
||||
*/
|
||||
class Location extends Entity
|
||||
{
|
||||
@ -23,15 +24,30 @@ class Location extends Entity
|
||||
*/
|
||||
const OSM_URL = 'https://www.openstreetmap.org/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const NOMINATIM_URL = 'https://nominatim.openstreetmap.org/';
|
||||
|
||||
public function __construct(
|
||||
protected string $name,
|
||||
protected ?string $geo = null,
|
||||
protected ?string $osm = null
|
||||
) {
|
||||
parent::__construct([
|
||||
'name' => $name,
|
||||
'geo' => $geo,
|
||||
'osm' => $osm
|
||||
]);
|
||||
}
|
||||
|
||||
public function getUrl(): string
|
||||
{
|
||||
if ($this->osm_id !== null) {
|
||||
if ($this->osm !== null) {
|
||||
return self::OSM_URL .
|
||||
['N' => 'node', 'W' => 'way', 'R' => 'relation'][
|
||||
substr($this->osm_id, 0, 1)
|
||||
] .
|
||||
['N' => 'node', 'W' => 'way', 'R' => 'relation'][substr($this->osm, 0, 1)] .
|
||||
'/' .
|
||||
substr($this->osm_id, 1);
|
||||
substr($this->osm, 1);
|
||||
}
|
||||
|
||||
if ($this->geo !== null) {
|
||||
@ -42,4 +58,49 @@ class Location extends Entity
|
||||
|
||||
return self::OSM_URL . 'search?query=' . urlencode($this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches places from Nominatim OpenStreetMap
|
||||
*
|
||||
* @return array<string, string>|null
|
||||
*/
|
||||
public function fetchOsmLocation(): self
|
||||
{
|
||||
$client = Services::curlrequest();
|
||||
|
||||
$response = $client->request(
|
||||
'GET',
|
||||
self::NOMINATIM_URL .
|
||||
'search.php?q=' .
|
||||
urlencode($this->name) .
|
||||
'&polygon_geojson=1&format=jsonv2',
|
||||
[
|
||||
'headers' => [
|
||||
'User-Agent' => 'Castopod/' . CP_VERSION,
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
],
|
||||
);
|
||||
|
||||
$places = json_decode(
|
||||
$response->getBody(),
|
||||
false,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
|
||||
if ($places === []) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (isset($places[0]->lat, $places[0]->lon)) {
|
||||
$this->attributes['geo'] = "geo:{$places[0]->lat},{$places[0]->lon}";
|
||||
}
|
||||
|
||||
if (isset($places[0]->osm_type, $places[0]->osm_id)) {
|
||||
$this->attributes['osm'] = strtoupper(substr($places[0]->osm_type, 0, 1)) . $places[0]->osm_id;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ use RuntimeException;
|
||||
*/
|
||||
class Note extends ActivityPubNote
|
||||
{
|
||||
protected ?Episode $episode;
|
||||
protected ?Episode $episode = null;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
|
@ -8,7 +8,9 @@
|
||||
|
||||
namespace App\Entities;
|
||||
|
||||
use App\Models\PersonModel;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
@ -20,16 +22,16 @@ use CodeIgniter\Entity\Entity;
|
||||
* @property string $image_mimetype
|
||||
* @property int $created_by
|
||||
* @property int $updated_by
|
||||
* @property string|null $group
|
||||
* @property string|null $role
|
||||
* @property Podcast|null $podcast
|
||||
* @property Episode|null $episode
|
||||
* @property string[]|null $roles
|
||||
*/
|
||||
class Person extends Entity
|
||||
{
|
||||
protected Image $image;
|
||||
protected ?Podcast $podcast;
|
||||
protected ?Episode $episode;
|
||||
|
||||
/**
|
||||
* @var string[]|null
|
||||
*/
|
||||
protected ?array $roles = null;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
@ -43,8 +45,6 @@ class Person extends Entity
|
||||
'image_mimetype' => 'string',
|
||||
'podcast_id' => '?integer',
|
||||
'episode_id' => '?integer',
|
||||
'group' => '?string',
|
||||
'role' => '?string',
|
||||
'created_by' => 'integer',
|
||||
'updated_by' => 'integer',
|
||||
];
|
||||
@ -73,4 +73,21 @@ class Person extends Entity
|
||||
$this->attributes['image_mimetype'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return stdClass[]
|
||||
*/
|
||||
public function getRoles(): array {
|
||||
if ($this->podcast_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Person must have a podcast_id before getting roles.',
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->roles === null) {
|
||||
$this->roles = (new PersonModel())->getPersonRoles($this->id, $this->podcast_id, $this->episode_id);
|
||||
}
|
||||
|
||||
return $this->roles;
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ use RuntimeException;
|
||||
* @property string $link
|
||||
* @property string $feed_url
|
||||
* @property string $title
|
||||
* @property string $description Holds text only description, striped of any markdown or html special characters
|
||||
* @property string|null $description Holds text only description, striped of any markdown or html special characters
|
||||
* @property string $description_markdown
|
||||
* @property string $description_html
|
||||
* @property Image $image
|
||||
@ -51,10 +51,10 @@ use RuntimeException;
|
||||
* @property bool $is_locked
|
||||
* @property string|null $imported_feed_url
|
||||
* @property string|null $new_feed_url
|
||||
* @property Location $location
|
||||
* @property Location|null $location
|
||||
* @property string|null $location_name
|
||||
* @property string|null $location_geo
|
||||
* @property string|null $location_osm_id
|
||||
* @property string|null $location_osm
|
||||
* @property string|null $payment_pointer
|
||||
* @property array|null $custom_rss
|
||||
* @property string $custom_rss_string
|
||||
@ -78,10 +78,10 @@ use RuntimeException;
|
||||
class Podcast extends Entity
|
||||
{
|
||||
protected string $link;
|
||||
protected ?Actor $actor;
|
||||
protected ?Actor $actor = null;
|
||||
protected Image $image;
|
||||
protected string $description;
|
||||
protected ?Category $category;
|
||||
protected ?string $description = null;
|
||||
protected ?Category $category = null;
|
||||
|
||||
/**
|
||||
* @var Category[]
|
||||
@ -123,7 +123,7 @@ class Podcast extends Entity
|
||||
*/
|
||||
protected $funding_platforms = [];
|
||||
|
||||
protected ?Location $location;
|
||||
protected ?Location $location = null;
|
||||
protected string $custom_rss_string;
|
||||
|
||||
/**
|
||||
@ -155,7 +155,7 @@ class Podcast extends Entity
|
||||
'new_feed_url' => '?string',
|
||||
'location_name' => '?string',
|
||||
'location_geo' => '?string',
|
||||
'location_osm_id' => '?string',
|
||||
'location_osm' => '?string',
|
||||
'payment_pointer' => '?string',
|
||||
'custom_rss' => '?json-array',
|
||||
'partner_id' => '?string',
|
||||
@ -331,17 +331,17 @@ class Podcast extends Entity
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
if ($this->description !== '') {
|
||||
return $this->description;
|
||||
if ($this->description === null) {
|
||||
$this->description = trim(
|
||||
(string) preg_replace(
|
||||
'~\s+~',
|
||||
' ',
|
||||
strip_tags($this->attributes['description_html']),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return trim(
|
||||
preg_replace(
|
||||
'~\s+~',
|
||||
' ',
|
||||
strip_tags($this->attributes['description_html']),
|
||||
),
|
||||
);
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -451,28 +451,25 @@ class Podcast extends Entity
|
||||
/**
|
||||
* Saves the location name and fetches OpenStreetMap info
|
||||
*/
|
||||
public function setLocation(?string $newLocationName = null): static
|
||||
public function setLocation(?Location $location = null): static
|
||||
{
|
||||
if ($newLocationName === null) {
|
||||
if ($location === null) {
|
||||
$this->attributes['location_name'] = null;
|
||||
$this->attributes['location_geo'] = null;
|
||||
$this->attributes['location_osm_id'] = null;
|
||||
$this->attributes['location_osm'] = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
helper('location');
|
||||
|
||||
$oldLocationName = $this->attributes['location_name'];
|
||||
|
||||
if (
|
||||
$oldLocationName === null ||
|
||||
$oldLocationName !== $newLocationName
|
||||
!isset($this->attributes['location_name']) ||
|
||||
$this->attributes['location_name'] !== $location->name
|
||||
) {
|
||||
$this->attributes['location_name'] = $newLocationName;
|
||||
$location->fetchOsmLocation();
|
||||
|
||||
if ($location = fetch_osm_location($newLocationName)) {
|
||||
$this->attributes['location_geo'] = $location['geo'];
|
||||
$this->attributes['location_osm_id'] = $location['osm_id'];
|
||||
}
|
||||
$this->attributes['location_name'] = $location->name;
|
||||
$this->attributes['location_geo'] = $location->geo;
|
||||
$this->attributes['location_osm'] = $location->osm;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -485,11 +482,11 @@ class Podcast extends Entity
|
||||
}
|
||||
|
||||
if ($this->location === null) {
|
||||
$this->location = new Location([
|
||||
'name' => $this->location_name,
|
||||
'geo' => $this->location_geo,
|
||||
'osm_id' => $this->location_osm_id,
|
||||
]);
|
||||
$this->location = new Location(
|
||||
$this->location_name,
|
||||
$this->location_geo,
|
||||
$this->location_osm,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->location;
|
||||
|
@ -27,9 +27,9 @@ use Myth\Auth\Entities\User as MythAuthUser;
|
||||
class User extends MythAuthUser
|
||||
{
|
||||
/**
|
||||
* @var Podcast[]
|
||||
* @var Podcast[]|null
|
||||
*/
|
||||
protected $podcasts = [];
|
||||
protected ?array $podcasts = null;
|
||||
|
||||
/**
|
||||
* Array of field names and the type of value to cast them as
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
use App\Entities\Location;
|
||||
use App\Entities\Person;
|
||||
use CodeIgniter\View\Table;
|
||||
use CodeIgniter\I18n\Time;
|
||||
|
||||
@ -291,13 +292,11 @@ if (!function_exists('publication_button')) {
|
||||
* Publication button component
|
||||
*
|
||||
* Displays the appropriate publication button depending on the publication status.
|
||||
*
|
||||
* @param boolean $publicationStatus the episode's publication status *
|
||||
*/
|
||||
function publication_button(
|
||||
int $podcastId,
|
||||
int $episodeId,
|
||||
bool $publicationStatus
|
||||
string $publicationStatus
|
||||
): string {
|
||||
switch ($publicationStatus) {
|
||||
case 'not_published':
|
||||
@ -416,3 +415,59 @@ if (!function_exists('location_link')) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('person_list')) {
|
||||
/**
|
||||
* Returns list of persons images
|
||||
*
|
||||
* @param Person[] $persons
|
||||
*/
|
||||
function person_list(array $persons, string $class = ''): string
|
||||
{
|
||||
if ($persons === []) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$personList = "<div class='flex w-full space-x-2 overflow-y-auto {$class}'>";
|
||||
|
||||
foreach ($persons as $person) {
|
||||
$personList .= anchor(
|
||||
$person->information_url ?? '#',
|
||||
"<img
|
||||
src='{$person->image->thumbnail_url}'
|
||||
alt='$person->full_name'
|
||||
class='object-cover w-12 h-12 rounded-full' />",
|
||||
[
|
||||
'class' =>
|
||||
'flex-shrink-0 focus:outline-none focus:ring focus:ring-inset',
|
||||
'target' => '_blank',
|
||||
'rel' => 'noreferrer noopener',
|
||||
'title' =>
|
||||
'<strong>' .
|
||||
$person->full_name .
|
||||
'</strong>' .
|
||||
implode(
|
||||
array_map(function ($role) {
|
||||
return '<br />' .
|
||||
lang(
|
||||
'PersonsTaxonomy.persons.' .
|
||||
$role->group .
|
||||
'.roles.' .
|
||||
$role->role .
|
||||
'.label',
|
||||
);
|
||||
}, $person->roles),
|
||||
),
|
||||
'data-toggle' => 'tooltip',
|
||||
'data-placement' => 'bottom',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
$personList .= '</div>';
|
||||
|
||||
return $personList;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -99,14 +99,14 @@ if (!function_exists('form_label')) {
|
||||
/**
|
||||
* Form Label Tag
|
||||
*
|
||||
* @param string $label_text The text to appear onscreen
|
||||
* @param string $text The text to appear onscreen
|
||||
* @param string $id The id the label applies to
|
||||
* @param array<string, string> $attributes Additional attributes
|
||||
* @param string $hintText Hint text to add next to the label
|
||||
* @param boolean $isOptional adds an optional text if true
|
||||
*/
|
||||
function form_label(
|
||||
string $label_text = '',
|
||||
string $text = '',
|
||||
string $id = '',
|
||||
array $attributes = [],
|
||||
string $hintText = '',
|
||||
@ -124,19 +124,19 @@ if (!function_exists('form_label')) {
|
||||
}
|
||||
}
|
||||
|
||||
$label_content = $label_text;
|
||||
$labelContent = $text;
|
||||
if ($isOptional) {
|
||||
$label_content .=
|
||||
$labelContent .=
|
||||
'<small class="ml-1 lowercase">(' .
|
||||
lang('Common.optional') .
|
||||
')</small>';
|
||||
}
|
||||
|
||||
if ($hintText !== '') {
|
||||
$label_content .= hint_tooltip($hintText, 'ml-1');
|
||||
$labelContent .= hint_tooltip($hintText, 'ml-1');
|
||||
}
|
||||
|
||||
return $label . '>' . $label_content . '</label>';
|
||||
return $label . '>' . $labelContent . '</label>';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,9 +54,9 @@ if (!function_exists('write_audio_file_tags')) {
|
||||
$APICdata = file_get_contents($cover->getRealPath());
|
||||
|
||||
// TODO: variables used for podcast specific tags
|
||||
// $podcast_url = $episode->podcast->link;
|
||||
// $podcast_feed_url = $episode->podcast->feed_url;
|
||||
// $episode_media_url = $episode->link;
|
||||
// $podcastUrl = $episode->podcast->link;
|
||||
// $podcastFeedUrl = $episode->podcast->feed_url;
|
||||
// $episodeMediaUrl = $episode->link;
|
||||
|
||||
// populate data array
|
||||
$TagData = [
|
||||
@ -74,7 +74,7 @@ if (!function_exists('write_audio_file_tags')) {
|
||||
],
|
||||
'genre' => ['Podcast'],
|
||||
'comment' => [$episode->description],
|
||||
'track_number' => [strval($episode->number)],
|
||||
'track_number' => [(string) $episode->number],
|
||||
'copyright_message' => [$episode->podcast->copyright],
|
||||
'publisher' => [
|
||||
empty($episode->podcast->publisher)
|
||||
|
@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
use Config\Services;
|
||||
|
||||
if (!function_exists('fetch_osm_location')) {
|
||||
/**
|
||||
* Fetches places from Nominatim OpenStreetMap
|
||||
*
|
||||
* TODO: move this to Location object?
|
||||
*
|
||||
* @return array<string, string>|null
|
||||
*/
|
||||
function fetch_osm_location(string $locationName): ?array
|
||||
{
|
||||
$osmObject = null;
|
||||
|
||||
try {
|
||||
$client = Services::curlrequest();
|
||||
|
||||
$response = $client->request(
|
||||
'GET',
|
||||
'https://nominatim.openstreetmap.org/search.php?q=' .
|
||||
urlencode($locationName) .
|
||||
'&polygon_geojson=1&format=jsonv2',
|
||||
[
|
||||
'headers' => [
|
||||
'User-Agent' => 'Castopod/' . CP_VERSION,
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
],
|
||||
);
|
||||
$places = json_decode(
|
||||
$response->getBody(),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
|
||||
$osmObject = [
|
||||
'geo' =>
|
||||
empty($places[0]['lat']) || empty($places[0]['lon'])
|
||||
? null
|
||||
: "geo:{$places[0]['lat']},{$places[0]['lon']}",
|
||||
'osm_id' => empty($places[0]['osm_type'])
|
||||
? null
|
||||
: strtoupper(substr($places[0]['osm_type'], 0, 1)) .
|
||||
$places[0]['osm_id'],
|
||||
];
|
||||
} catch (Exception $exception) {
|
||||
//If things go wrong the show must go on
|
||||
log_message('critical', $exception);
|
||||
}
|
||||
|
||||
return $osmObject;
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ if (!function_exists('slugify')) {
|
||||
// replace non letter or digits by -
|
||||
$text = preg_replace('~[^\pL\d]+~u', '-', $text);
|
||||
|
||||
$unwanted_array = [
|
||||
$unwanted = [
|
||||
'Š' => 'S',
|
||||
'š' => 's',
|
||||
'Đ' => 'Dj',
|
||||
@ -107,7 +107,7 @@ if (!function_exists('slugify')) {
|
||||
'/' => '-',
|
||||
' ' => '-',
|
||||
];
|
||||
$text = strtr($text, $unwanted_array);
|
||||
$text = strtr($text, $unwanted);
|
||||
|
||||
// transliterate
|
||||
$text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
|
||||
|
@ -23,31 +23,31 @@ if (!function_exists('get_rss_feed')) {
|
||||
{
|
||||
$episodes = $podcast->episodes;
|
||||
|
||||
$itunes_namespace = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
|
||||
$itunesNamespace = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
|
||||
|
||||
$podcast_namespace =
|
||||
$podcastNamespace =
|
||||
'https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md';
|
||||
|
||||
$rss = new SimpleRSSElement(
|
||||
"<?xml version='1.0' encoding='utf-8'?><rss version='2.0' xmlns:itunes='{$itunes_namespace}' xmlns:podcast='{$podcast_namespace}' xmlns:content='http://purl.org/rss/1.0/modules/content/'></rss>",
|
||||
"<?xml version='1.0' encoding='utf-8'?><rss version='2.0' xmlns:itunes='{$itunesNamespace}' xmlns:podcast='{$podcastNamespace}' xmlns:content='http://purl.org/rss/1.0/modules/content/'></rss>",
|
||||
);
|
||||
|
||||
$channel = $rss->addChild('channel');
|
||||
|
||||
$atom_link = $channel->addChild(
|
||||
$atomLink = $channel->addChild(
|
||||
'atom:link',
|
||||
null,
|
||||
'http://www.w3.org/2005/Atom',
|
||||
);
|
||||
$atom_link->addAttribute('href', $podcast->feed_url);
|
||||
$atom_link->addAttribute('rel', 'self');
|
||||
$atom_link->addAttribute('type', 'application/rss+xml');
|
||||
$atomLink->addAttribute('href', $podcast->feed_url);
|
||||
$atomLink->addAttribute('rel', 'self');
|
||||
$atomLink->addAttribute('type', 'application/rss+xml');
|
||||
|
||||
if ($podcast->new_feed_url !== null) {
|
||||
$channel->addChild(
|
||||
'new-feed-url',
|
||||
$podcast->new_feed_url,
|
||||
$itunes_namespace,
|
||||
$itunesNamespace,
|
||||
);
|
||||
}
|
||||
|
||||
@ -65,33 +65,30 @@ if (!function_exists('get_rss_feed')) {
|
||||
$channel->addChild('title', $podcast->title);
|
||||
$channel->addChildWithCDATA('description', $podcast->description_html);
|
||||
|
||||
$itunes_image = $channel->addChild('image', null, $itunes_namespace);
|
||||
$itunesImage = $channel->addChild('image', null, $itunesNamespace);
|
||||
|
||||
// FIXME: This should be downsized to 1400x1400
|
||||
$itunes_image->addAttribute('href', $podcast->image->url);
|
||||
$itunesImage->addAttribute('href', $podcast->image->url);
|
||||
|
||||
$channel->addChild('language', $podcast->language_code);
|
||||
if ($podcast->location !== null) {
|
||||
$locationElement = $channel->addChild(
|
||||
'location',
|
||||
htmlspecialchars($podcast->location->name),
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
if ($podcast->location->geo !== null) {
|
||||
$locationElement->addAttribute('geo', $podcast->location->geo);
|
||||
}
|
||||
if ($podcast->location->osm_id !== null) {
|
||||
$locationElement->addAttribute(
|
||||
'osm',
|
||||
$podcast->location->osm_id,
|
||||
);
|
||||
if ($podcast->location->osm !== null) {
|
||||
$locationElement->addAttribute('osm', $podcast->location->osm);
|
||||
}
|
||||
}
|
||||
if ($podcast->payment_pointer !== null) {
|
||||
$valueElement = $channel->addChild(
|
||||
'value',
|
||||
null,
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$valueElement->addAttribute('type', 'webmonetization');
|
||||
$valueElement->addAttribute('method', '');
|
||||
@ -99,7 +96,7 @@ if (!function_exists('get_rss_feed')) {
|
||||
$recipientElement = $valueElement->addChild(
|
||||
'valueRecipient',
|
||||
null,
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$recipientElement->addAttribute('name', $podcast->owner_name);
|
||||
$recipientElement->addAttribute('type', 'ILP');
|
||||
@ -113,14 +110,14 @@ if (!function_exists('get_rss_feed')) {
|
||||
->addChild(
|
||||
'locked',
|
||||
$podcast->is_locked ? 'yes' : 'no',
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
)
|
||||
->addAttribute('owner', $podcast->owner_email);
|
||||
if ($podcast->imported_feed_url !== null) {
|
||||
$channel->addChild(
|
||||
'previousUrl',
|
||||
$podcast->imported_feed_url,
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
}
|
||||
|
||||
@ -128,7 +125,7 @@ if (!function_exists('get_rss_feed')) {
|
||||
$podcastingPlatformElement = $channel->addChild(
|
||||
'id',
|
||||
null,
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$podcastingPlatformElement->addAttribute(
|
||||
'platform',
|
||||
@ -152,7 +149,7 @@ if (!function_exists('get_rss_feed')) {
|
||||
$socialPlatformElement = $channel->addChild(
|
||||
'social',
|
||||
$socialPlatform->link_content,
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$socialPlatformElement->addAttribute(
|
||||
'platform',
|
||||
@ -170,7 +167,7 @@ if (!function_exists('get_rss_feed')) {
|
||||
$fundingPlatformElement = $channel->addChild(
|
||||
'funding',
|
||||
$fundingPlatform->link_content,
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$fundingPlatformElement->addAttribute(
|
||||
'platform',
|
||||
@ -188,7 +185,7 @@ if (!function_exists('get_rss_feed')) {
|
||||
$podcastPersonElement = $channel->addChild(
|
||||
'person',
|
||||
htmlspecialchars($podcastPerson->full_name),
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
|
||||
if (
|
||||
@ -242,29 +239,29 @@ if (!function_exists('get_rss_feed')) {
|
||||
$channel->addChild(
|
||||
'explicit',
|
||||
$podcast->parental_advisory === 'explicit' ? 'true' : 'false',
|
||||
$itunes_namespace,
|
||||
$itunesNamespace,
|
||||
);
|
||||
|
||||
$channel->addChild(
|
||||
'author',
|
||||
$podcast->publisher ? $podcast->publisher : $podcast->owner_name,
|
||||
$itunes_namespace,
|
||||
$itunesNamespace,
|
||||
);
|
||||
$channel->addChild('link', $podcast->link);
|
||||
|
||||
$owner = $channel->addChild('owner', null, $itunes_namespace);
|
||||
$owner = $channel->addChild('owner', null, $itunesNamespace);
|
||||
|
||||
$owner->addChild('name', $podcast->owner_name, $itunes_namespace);
|
||||
$owner->addChild('name', $podcast->owner_name, $itunesNamespace);
|
||||
|
||||
$owner->addChild('email', $podcast->owner_email, $itunes_namespace);
|
||||
$owner->addChild('email', $podcast->owner_email, $itunesNamespace);
|
||||
|
||||
$channel->addChild('type', $podcast->type, $itunes_namespace);
|
||||
$channel->addChild('type', $podcast->type, $itunesNamespace);
|
||||
$podcast->copyright &&
|
||||
$channel->addChild('copyright', $podcast->copyright);
|
||||
$podcast->is_blocked &&
|
||||
$channel->addChild('block', 'Yes', $itunes_namespace);
|
||||
$channel->addChild('block', 'Yes', $itunesNamespace);
|
||||
$podcast->is_completed &&
|
||||
$channel->addChild('complete', 'Yes', $itunes_namespace);
|
||||
$channel->addChild('complete', 'Yes', $itunesNamespace);
|
||||
|
||||
$image = $channel->addChild('image');
|
||||
$image->addChild('url', $podcast->image->feed_url);
|
||||
@ -304,7 +301,7 @@ if (!function_exists('get_rss_feed')) {
|
||||
$locationElement = $item->addChild(
|
||||
'location',
|
||||
htmlspecialchars($episode->location->name),
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
if ($episode->location->geo !== null) {
|
||||
$locationElement->addAttribute(
|
||||
@ -312,10 +309,10 @@ if (!function_exists('get_rss_feed')) {
|
||||
$episode->location->geo,
|
||||
);
|
||||
}
|
||||
if ($episode->location->osm_id !== null) {
|
||||
if ($episode->location->osm !== null) {
|
||||
$locationElement->addAttribute(
|
||||
'osm',
|
||||
$episode->location->osm_id,
|
||||
$episode->location->osm,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -326,15 +323,15 @@ if (!function_exists('get_rss_feed')) {
|
||||
$item->addChild(
|
||||
'duration',
|
||||
$episode->audio_file_duration,
|
||||
$itunes_namespace,
|
||||
$itunesNamespace,
|
||||
);
|
||||
$item->addChild('link', $episode->link);
|
||||
$episode_itunes_image = $item->addChild(
|
||||
$episodeItunesImage = $item->addChild(
|
||||
'image',
|
||||
null,
|
||||
$itunes_namespace,
|
||||
$itunesNamespace,
|
||||
);
|
||||
$episode_itunes_image->addAttribute(
|
||||
$episodeItunesImage->addAttribute(
|
||||
'href',
|
||||
$episode->image->feed_url,
|
||||
);
|
||||
@ -345,24 +342,24 @@ if (!function_exists('get_rss_feed')) {
|
||||
$episode->parental_advisory === 'explicit'
|
||||
? 'true'
|
||||
: 'false',
|
||||
$itunes_namespace,
|
||||
$itunesNamespace,
|
||||
);
|
||||
|
||||
$episode->number &&
|
||||
$item->addChild('episode', $episode->number, $itunes_namespace);
|
||||
$item->addChild('episode', $episode->number, $itunesNamespace);
|
||||
$episode->season_number &&
|
||||
$item->addChild(
|
||||
'season',
|
||||
$episode->season_number,
|
||||
$itunes_namespace,
|
||||
$itunesNamespace,
|
||||
);
|
||||
$item->addChild('episodeType', $episode->type, $itunes_namespace);
|
||||
$item->addChild('episodeType', $episode->type, $itunesNamespace);
|
||||
|
||||
if ($episode->transcript_file_url) {
|
||||
$transcriptElement = $item->addChild(
|
||||
'transcript',
|
||||
null,
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$transcriptElement->addAttribute(
|
||||
'url',
|
||||
@ -387,7 +384,7 @@ if (!function_exists('get_rss_feed')) {
|
||||
$chaptersElement = $item->addChild(
|
||||
'chapters',
|
||||
null,
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$chaptersElement->addAttribute(
|
||||
'url',
|
||||
@ -403,7 +400,7 @@ if (!function_exists('get_rss_feed')) {
|
||||
$soundbiteElement = $item->addChild(
|
||||
'soundbite',
|
||||
empty($soundbite->label) ? null : $soundbite->label,
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$soundbiteElement->addAttribute(
|
||||
'start_time',
|
||||
@ -419,7 +416,7 @@ if (!function_exists('get_rss_feed')) {
|
||||
$episodePersonElement = $item->addChild(
|
||||
'person',
|
||||
htmlspecialchars($episodePerson->full_name),
|
||||
$podcast_namespace,
|
||||
$podcastNamespace,
|
||||
);
|
||||
if (
|
||||
!empty($episodePerson->role) &&
|
||||
@ -461,7 +458,7 @@ if (!function_exists('get_rss_feed')) {
|
||||
}
|
||||
|
||||
$episode->is_blocked &&
|
||||
$item->addChild('block', 'Yes', $itunes_namespace);
|
||||
$item->addChild('block', 'Yes', $itunesNamespace);
|
||||
|
||||
if (!empty($episode->custom_rss)) {
|
||||
array_to_rss(
|
||||
@ -483,10 +480,10 @@ if (!function_exists('add_category_tag')) {
|
||||
*/
|
||||
function add_category_tag(SimpleXMLElement $node, Category $category): void
|
||||
{
|
||||
$itunes_namespace = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
|
||||
$itunesNamespace = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
|
||||
|
||||
$itunes_category = $node->addChild('category', '', $itunes_namespace);
|
||||
$itunes_category->addAttribute(
|
||||
$itunesCategory = $node->addChild('category', '', $itunesNamespace);
|
||||
$itunesCategory->addAttribute(
|
||||
'text',
|
||||
$category->parent !== null
|
||||
? $category->parent->apple_category
|
||||
@ -494,12 +491,12 @@ if (!function_exists('add_category_tag')) {
|
||||
);
|
||||
|
||||
if ($category->parent !== null) {
|
||||
$itunes_category_child = $itunes_category->addChild(
|
||||
$itunesCategoryChild = $itunesCategory->addChild(
|
||||
'category',
|
||||
'',
|
||||
$itunes_namespace,
|
||||
$itunesNamespace,
|
||||
);
|
||||
$itunes_category_child->addAttribute(
|
||||
$itunesCategoryChild->addAttribute(
|
||||
'text',
|
||||
$category->apple_category,
|
||||
);
|
||||
|
@ -16,16 +16,16 @@ if (!function_exists('icon')) {
|
||||
*/
|
||||
function icon(string $name, string $class = ''): string
|
||||
{
|
||||
$svg_contents = file_get_contents('assets/icons/' . $name . '.svg');
|
||||
$svgContents = file_get_contents('assets/icons/' . $name . '.svg');
|
||||
if ($class !== '') {
|
||||
$svg_contents = str_replace(
|
||||
$svgContents = str_replace(
|
||||
'<svg',
|
||||
'<svg class="' . $class . '"',
|
||||
$svg_contents,
|
||||
$svgContents,
|
||||
);
|
||||
}
|
||||
|
||||
return $svg_contents;
|
||||
return $svgContents;
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,14 +39,14 @@ if (!function_exists('svg')) {
|
||||
*/
|
||||
function svg(string $name, ?string $class = null): string
|
||||
{
|
||||
$svg_contents = file_get_contents('assets/images/' . $name . '.svg');
|
||||
$svgContents = file_get_contents('assets/images/' . $name . '.svg');
|
||||
if ($class) {
|
||||
$svg_contents = str_replace(
|
||||
$svgContents = str_replace(
|
||||
'<svg',
|
||||
'<svg class="' . $class . '"',
|
||||
$svg_contents,
|
||||
$svgContents,
|
||||
);
|
||||
}
|
||||
return $svg_contents;
|
||||
return $svgContents;
|
||||
}
|
||||
}
|
||||
|
@ -27,22 +27,6 @@ if (!function_exists('host_url')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('current_season_url')) {
|
||||
/**
|
||||
* Return the podcast URL with season number to use in views
|
||||
*/
|
||||
function current_season_url(): string
|
||||
{
|
||||
$season_query_string = '';
|
||||
if (isset($_GET['season'])) {
|
||||
$season_query_string = '?season=' . $_GET['season'];
|
||||
} elseif (isset($_GET['year'])) {
|
||||
$season_query_string = '?year=' . $_GET['year'];
|
||||
}
|
||||
return current_url() . $season_query_string;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('extract_params_from_episode_uri')) {
|
||||
|
@ -85,7 +85,7 @@ class ActivityRequest
|
||||
$date = Time::now('GMT')->format('D, d M Y H:i:s T');
|
||||
$digest = 'SHA-256=' . base64_encode($this->getBodyDigest());
|
||||
$contentType = $this->options['headers']['Content-Type'];
|
||||
$contentLength = strval(strlen($this->request->getBody()));
|
||||
$contentLength = (string) strlen($this->request->getBody());
|
||||
$userAgent = 'Castopod';
|
||||
|
||||
$plainText = "(request-target): post {$path}\nhost: {$host}\ndate: {$date}\ndigest: {$digest}\ncontent-type: {$contentType}\ncontent-length: {$contentLength}\nuser-agent: {$userAgent}";
|
||||
|
@ -182,7 +182,7 @@ if (!function_exists('create_preview_card_from_url')) {
|
||||
|
||||
// Check that, at least, the url and title are set
|
||||
if ($media->url && $media->title) {
|
||||
$preview_card = new PreviewCard([
|
||||
$newPreviewCard = new PreviewCard([
|
||||
'url' => (string) $url,
|
||||
'title' => $media->title,
|
||||
'description' => $media->description,
|
||||
@ -199,15 +199,15 @@ if (!function_exists('create_preview_card_from_url')) {
|
||||
|
||||
if (
|
||||
!($newPreviewCardId = model('PreviewCardModel')->insert(
|
||||
$preview_card,
|
||||
$newPreviewCard,
|
||||
true,
|
||||
))
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$preview_card->id = $newPreviewCardId;
|
||||
return $preview_card;
|
||||
$newPreviewCard->id = $newPreviewCardId;
|
||||
return $newPreviewCard;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ class HttpSignature
|
||||
|
||||
public function __construct(IncomingRequest $request = null)
|
||||
{
|
||||
if (is_null($request)) {
|
||||
if ($request === null) {
|
||||
$request = Services::request();
|
||||
}
|
||||
|
||||
|
@ -39,18 +39,21 @@ class AnalyticsController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
public function getData(int $podcastId, int $episodeId): ResponseInterface
|
||||
{
|
||||
$analytics_model = new $this->className();
|
||||
public function getData(
|
||||
int $podcastId,
|
||||
?int $episodeId = null
|
||||
): ResponseInterface {
|
||||
$analyticsModel = new $this->className();
|
||||
$methodName = $this->methodName;
|
||||
if ($episodeId !== 0) {
|
||||
|
||||
if ($episodeId === null) {
|
||||
return $this->response->setJSON(
|
||||
$analytics_model->$methodName($podcastId, $episodeId),
|
||||
$analyticsModel->$methodName($podcastId),
|
||||
);
|
||||
}
|
||||
|
||||
return $this->response->setJSON(
|
||||
$analytics_model->$methodName($podcastId),
|
||||
$analyticsModel->$methodName($podcastId, $episodeId),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -26,15 +26,15 @@ class SimpleRSSElement extends SimpleXMLElement
|
||||
string $value = '',
|
||||
?string $namespace = null
|
||||
) {
|
||||
$new_child = parent::addChild($name, '', $namespace);
|
||||
$newChild = parent::addChild($name, '', $namespace);
|
||||
|
||||
if ($new_child !== null) {
|
||||
$node = dom_import_simplexml($new_child);
|
||||
if ($newChild !== null) {
|
||||
$node = dom_import_simplexml($newChild);
|
||||
$no = $node->ownerDocument;
|
||||
$node->appendChild($no->createCDATASection($value));
|
||||
}
|
||||
|
||||
return $new_child;
|
||||
return $newChild;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,14 +49,14 @@ class SimpleRSSElement extends SimpleXMLElement
|
||||
*/
|
||||
public function addChild($name, $value = null, $namespace = null)
|
||||
{
|
||||
$new_child = parent::addChild($name, '', $namespace);
|
||||
$newChild = parent::addChild($name, '', $namespace);
|
||||
|
||||
if ($new_child !== null) {
|
||||
$node = dom_import_simplexml($new_child);
|
||||
if ($newChild !== null) {
|
||||
$node = dom_import_simplexml($newChild);
|
||||
$no = $node->ownerDocument;
|
||||
$node->appendChild($no->createTextNode(esc($value)));
|
||||
}
|
||||
|
||||
return $new_child;
|
||||
return $newChild;
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ class EpisodeModel extends Model
|
||||
'is_blocked',
|
||||
'location_name',
|
||||
'location_geo',
|
||||
'location_osm_id',
|
||||
'location_osm',
|
||||
'custom_rss',
|
||||
'favourites_total',
|
||||
'reblogs_total',
|
||||
|
@ -19,6 +19,7 @@ class PersonModel extends Model
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'persons';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@ -98,209 +99,39 @@ class PersonModel extends Model
|
||||
return $this->where('full_name', $fullName)->first();
|
||||
}
|
||||
|
||||
public function addPerson(
|
||||
string $fullName,
|
||||
?string $informationUrl,
|
||||
string $image
|
||||
): int|bool {
|
||||
$person = new Person([
|
||||
'full_name' => $fullName,
|
||||
'unique_name' => slugify($fullName),
|
||||
'information_url' => $informationUrl,
|
||||
'image' => new Image(download_file($image)),
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
]);
|
||||
|
||||
return $this->insert($person);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Person[]
|
||||
* @return stdClass[]
|
||||
*/
|
||||
public function getEpisodePersons(int $podcastId, int $episodeId): array
|
||||
{
|
||||
$cacheName = "podcast#{$podcastId}_episode#{$episodeId}_persons";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this->db
|
||||
->table('episodes_persons')
|
||||
->select('episodes_persons.*')
|
||||
->where('episode_id', $episodeId)
|
||||
->join('persons', 'person_id=persons.id')
|
||||
->orderby('full_name')
|
||||
->findAll();
|
||||
public function getPersonRoles(int $personId, int $podcastId, ?int $episodeId): array {
|
||||
if ($episodeId) {
|
||||
$cacheName = "podcast#{$podcastId}_episode#{$episodeId}_person#{$personId}_roles";
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this
|
||||
->select('episodes_persons.person_group as group, episodes_persons.person_role as role')
|
||||
->join('episodes_persons', 'persons.id = episodes_persons.person_id')
|
||||
->where('persons.id', $personId)
|
||||
->where('episodes_persons.episode_id', $episodeId)
|
||||
->get()
|
||||
->getResultObject();
|
||||
}
|
||||
} else {
|
||||
$cacheName = "podcast#{$podcastId}_person#{$personId}_roles";
|
||||
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this
|
||||
->select('podcasts_persons.person_group as group, podcasts_persons.person_role as role')
|
||||
->join('podcasts_persons', 'persons.id = podcasts_persons.person_id')
|
||||
->where('persons.id', $personId)
|
||||
->where('podcasts_persons.podcast_id', $podcastId)
|
||||
->get()
|
||||
->getResultObject();
|
||||
}
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Person[]
|
||||
*/
|
||||
public function getPodcastPersons(int $podcastId): array
|
||||
{
|
||||
$cacheName = "podcast#{$podcastId}_persons";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this->db
|
||||
->table('podcasts_persons')
|
||||
->select('podcasts_persons.*')
|
||||
->where('podcast_id', $podcastId)
|
||||
->join('persons', 'person_id=persons.id')
|
||||
->orderby('full_name')
|
||||
->findAll();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
public function addEpisodePerson(
|
||||
int $podcastId,
|
||||
int $episodeId,
|
||||
int $personId,
|
||||
string $group,
|
||||
string $role
|
||||
): int|bool {
|
||||
return $this->db->table('episodes_persons')->insert([
|
||||
'podcast_id' => $podcastId,
|
||||
'episode_id' => $episodeId,
|
||||
'person_id' => $personId,
|
||||
'person_group' => $group,
|
||||
'person_role' => $role,
|
||||
]);
|
||||
}
|
||||
|
||||
public function addPodcastPerson(
|
||||
int $podcastId,
|
||||
int $personId,
|
||||
string $group,
|
||||
string $role
|
||||
): int|bool {
|
||||
return $this->db->table('podcasts_persons')->insert([
|
||||
'podcast_id' => $podcastId,
|
||||
'person_id' => $personId,
|
||||
'person_group' => $group,
|
||||
'person_role' => $role,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add persons to podcast
|
||||
*
|
||||
* @param array<string> $persons
|
||||
* @param array<string, string> $groupsRoles
|
||||
*
|
||||
* @return bool|int Number of rows inserted or FALSE on failure
|
||||
*/
|
||||
public function addPodcastPersons(
|
||||
int $podcastId,
|
||||
array $persons = [],
|
||||
array $groupsRoles = []
|
||||
): int|bool {
|
||||
if ($persons === []) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->clearCache(['podcast_id' => $podcastId]);
|
||||
$data = [];
|
||||
foreach ($persons as $person) {
|
||||
if ($groupsRoles === []) {
|
||||
$data[] = [
|
||||
'podcast_id' => $podcastId,
|
||||
'person_id' => $person,
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($groupsRoles as $group_role) {
|
||||
$group_role = explode(',', $group_role);
|
||||
$data[] = [
|
||||
'podcast_id' => $podcastId,
|
||||
'person_id' => $person,
|
||||
'person_group' => $group_role[0],
|
||||
'person_role' => $group_role[1],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->insertBatch($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add persons to episode
|
||||
*
|
||||
* @return BaseResult|bool Number of rows inserted or FALSE on failure
|
||||
*/
|
||||
public function removePodcastPersons(int $podcastId, int $personId): BaseResult|bool
|
||||
{
|
||||
return $this->delete([
|
||||
'id' => $personId,
|
||||
'podcast_id' => $podcastId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add persons to episode
|
||||
*
|
||||
* @param int[] $personIds
|
||||
* @param string[] $groups_roles
|
||||
*
|
||||
* @return bool|int Number of rows inserted or FALSE on failure
|
||||
*/
|
||||
public function addEpisodePersons(
|
||||
int $podcastId,
|
||||
int $episodeId,
|
||||
array $personIds,
|
||||
array $groups_roles
|
||||
): bool|int {
|
||||
if (!empty($personIds)) {
|
||||
$this->clearCache([
|
||||
'episode_id' => $episodeId,
|
||||
]);
|
||||
|
||||
$data = [];
|
||||
foreach ($personIds as $personId) {
|
||||
if ($groups_roles !== []) {
|
||||
foreach ($groups_roles as $group_role) {
|
||||
$group_role = explode(',', $group_role);
|
||||
$data[] = [
|
||||
'podcast_id' => $podcastId,
|
||||
'episode_id' => $episodeId,
|
||||
'person_id' => $personId,
|
||||
'person_group' => $group_role[0],
|
||||
'person_role' => $group_role[1],
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$data[] = [
|
||||
'podcast_id' => $podcastId,
|
||||
'episode_id' => $episodeId,
|
||||
'person_id' => $personId,
|
||||
];
|
||||
}
|
||||
}
|
||||
return $this->insertBatch($data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BaseResult|bool
|
||||
*/
|
||||
public function removeEpisodePersons(
|
||||
int $podcastId,
|
||||
int $episodeId,
|
||||
int $personId
|
||||
): BaseResult|bool {
|
||||
return $this->delete([
|
||||
'podcast_id' => $podcastId,
|
||||
'episode_id' => $episodeId,
|
||||
'id' => $personId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
@ -342,7 +173,7 @@ class PersonModel extends Model
|
||||
foreach ($group['roles'] as $role_key => $role) {
|
||||
$options[
|
||||
"{$group_key},{$role_key}"
|
||||
] = "{$group['label']} ▸ {$role['label']}";
|
||||
] = "{$group['label']} › {$role['label']}";
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,6 +183,209 @@ class PersonModel extends Model
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function addPerson(
|
||||
string $fullName,
|
||||
?string $informationUrl,
|
||||
string $image
|
||||
): int|bool {
|
||||
$person = new Person([
|
||||
'full_name' => $fullName,
|
||||
'unique_name' => slugify($fullName),
|
||||
'information_url' => $informationUrl,
|
||||
'image' => new Image(download_file($image)),
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
]);
|
||||
|
||||
return $this->insert($person);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Person[]
|
||||
*/
|
||||
public function getEpisodePersons(int $podcastId, int $episodeId): array
|
||||
{
|
||||
$cacheName = "podcast#{$podcastId}_episode#{$episodeId}_persons";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this
|
||||
->select('persons.*, episodes_persons.podcast_id, episodes_persons.episode_id')
|
||||
->distinct()
|
||||
->join('episodes_persons', 'persons.id = episodes_persons.person_id')
|
||||
->where('episodes_persons.episode_id', $episodeId)
|
||||
->orderby('persons.full_name')
|
||||
->findAll();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Person[]
|
||||
*/
|
||||
public function getPodcastPersons(int $podcastId): array
|
||||
{
|
||||
$cacheName = "podcast#{$podcastId}_persons";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this
|
||||
->select('persons.*, podcasts_persons.podcast_id as podcast_id')
|
||||
->distinct()
|
||||
->join('podcasts_persons', 'persons.id=podcasts_persons.person_id')
|
||||
->where('podcasts_persons.podcast_id', $podcastId)
|
||||
->orderby('persons.full_name')
|
||||
->findAll();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
public function addEpisodePerson(
|
||||
int $podcastId,
|
||||
int $episodeId,
|
||||
int $personId,
|
||||
string $groupSlug,
|
||||
string $roleSlug
|
||||
): int|bool {
|
||||
return $this->db->table('episodes_persons')->insert([
|
||||
'podcast_id' => $podcastId,
|
||||
'episode_id' => $episodeId,
|
||||
'person_id' => $personId,
|
||||
'person_group' => $groupSlug,
|
||||
'person_role' => $roleSlug,
|
||||
]);
|
||||
}
|
||||
|
||||
public function addPodcastPerson(
|
||||
int $podcastId,
|
||||
int $personId,
|
||||
string $groupSlug,
|
||||
string $roleSlug
|
||||
): int|bool {
|
||||
return $this->db->table('podcasts_persons')->insert([
|
||||
'podcast_id' => $podcastId,
|
||||
'person_id' => $personId,
|
||||
'person_group' => $groupSlug,
|
||||
'person_role' => $roleSlug,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add persons to podcast
|
||||
*
|
||||
* @param array<string> $persons
|
||||
* @param array<string, string> $groupsRoles
|
||||
*
|
||||
* @return bool|int Number of rows inserted or FALSE on failure
|
||||
*/
|
||||
public function addPodcastPersons(
|
||||
int $podcastId,
|
||||
array $persons = [],
|
||||
array $roles = []
|
||||
): int|bool {
|
||||
if ($persons === []) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cache()->delete("podcast#{$podcastId}_persons");
|
||||
(new PodcastModel())->clearCache(['id' => $podcastId]);
|
||||
|
||||
$data = [];
|
||||
foreach ($persons as $person) {
|
||||
if ($roles === []) {
|
||||
$data[] = [
|
||||
'podcast_id' => $podcastId,
|
||||
'person_id' => $person,
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$groupRole = explode(',', $role);
|
||||
$data[] = [
|
||||
'podcast_id' => $podcastId,
|
||||
'person_id' => $person,
|
||||
'person_group' => $groupRole[0],
|
||||
'person_role' => $groupRole[1],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->db->table('podcasts_persons')->insertBatch($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add persons to episode
|
||||
*
|
||||
* @return BaseResult|bool Number of rows inserted or FALSE on failure
|
||||
*/
|
||||
public function removePersonFromPodcast(int $podcastId, int $personId): BaseResult|bool
|
||||
{
|
||||
return $this->db->table('podcasts_persons')->delete([
|
||||
'podcast_id' => $podcastId,
|
||||
'person_id' => $personId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add persons to episode
|
||||
*
|
||||
* @param int[] $personIds
|
||||
* @param string[] $groupsRoles
|
||||
*
|
||||
* @return bool|int Number of rows inserted or FALSE on failure
|
||||
*/
|
||||
public function addEpisodePersons(
|
||||
int $podcastId,
|
||||
int $episodeId,
|
||||
array $personIds,
|
||||
array $groupsRoles
|
||||
): bool|int {
|
||||
if (!empty($personIds)) {
|
||||
(new EpisodeModel())->clearCache(['id' => $episodeId]);
|
||||
|
||||
$data = [];
|
||||
foreach ($personIds as $personId) {
|
||||
if ($groupsRoles !== []) {
|
||||
foreach ($groupsRoles as $groupRole) {
|
||||
$groupRole = explode(',', $groupRole);
|
||||
$data[] = [
|
||||
'podcast_id' => $podcastId,
|
||||
'episode_id' => $episodeId,
|
||||
'person_id' => $personId,
|
||||
'person_group' => $groupRole[0],
|
||||
'person_role' => $groupRole[1],
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$data[] = [
|
||||
'podcast_id' => $podcastId,
|
||||
'episode_id' => $episodeId,
|
||||
'person_id' => $personId,
|
||||
];
|
||||
}
|
||||
}
|
||||
return $this->db->table('episodes_persons')->insertBatch($data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BaseResult|bool
|
||||
*/
|
||||
public function removePersonFromEpisode(
|
||||
int $podcastId,
|
||||
int $episodeId,
|
||||
int $personId
|
||||
): BaseResult|bool {
|
||||
return $this->db->table('episodes_persons')->delete([
|
||||
'podcast_id' => $podcastId,
|
||||
'episode_id' => $episodeId,
|
||||
'person_id' => $personId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*
|
||||
@ -359,12 +393,10 @@ class PersonModel extends Model
|
||||
*/
|
||||
protected function clearCache(array $data): array
|
||||
{
|
||||
$person = (new PersonModel())->find(
|
||||
is_array($data['id']) ? $data['id'][0] : $data['id'],
|
||||
);
|
||||
$personId = is_array($data['id']) ? $data['id']['id'] : $data['id'];
|
||||
|
||||
cache()->delete('person_options');
|
||||
cache()->delete("person#{$person->id}");
|
||||
cache()->delete("person#{$personId}");
|
||||
|
||||
// clear cache for every credits page
|
||||
cache()->deleteMatching('page_credits_*');
|
||||
|
@ -53,7 +53,7 @@ class PodcastModel extends Model
|
||||
'is_locked',
|
||||
'location_name',
|
||||
'location_geo',
|
||||
'location_osm_id',
|
||||
'location_osm',
|
||||
'payment_pointer',
|
||||
'custom_rss',
|
||||
'partner_id',
|
||||
@ -218,11 +218,11 @@ class PodcastModel extends Model
|
||||
->delete();
|
||||
}
|
||||
|
||||
public function getContributorGroupId(int $userId, int $podcastId): int|false
|
||||
public function getContributorGroupId(int $userId, int|string $podcastId): int|false
|
||||
{
|
||||
if (!is_numeric($podcastId)) {
|
||||
// identifier is the podcast name, request must be a join
|
||||
$user_podcast = $this->db
|
||||
$userPodcast = $this->db
|
||||
->table('podcasts_users')
|
||||
->select('group_id, user_id')
|
||||
->join('podcasts', 'podcasts.id = podcasts_users.podcast_id')
|
||||
@ -233,7 +233,7 @@ class PodcastModel extends Model
|
||||
->get()
|
||||
->getResultObject();
|
||||
} else {
|
||||
$user_podcast = $this->db
|
||||
$userPodcast = $this->db
|
||||
->table('podcasts_users')
|
||||
->select('group_id')
|
||||
->where([
|
||||
@ -244,8 +244,8 @@ class PodcastModel extends Model
|
||||
->getResultObject();
|
||||
}
|
||||
|
||||
return count($user_podcast) > 0
|
||||
? $user_podcast[0]->group_id
|
||||
return count($userPodcast) > 0
|
||||
? $userPodcast[0]->group_id
|
||||
: false;
|
||||
}
|
||||
|
||||
@ -446,7 +446,7 @@ class PodcastModel extends Model
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
protected function clearCache(array $data): array
|
||||
public function clearCache(array $data): array
|
||||
{
|
||||
$podcast = (new PodcastModel())->getPodcastById(
|
||||
is_array($data['id']) ? $data['id'][0] : $data['id'],
|
||||
|
@ -5,7 +5,7 @@
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('pageTitle') ?>
|
||||
<?= lang('Person.episode_form.title') ?> (<?= count($episodePersons) ?>)
|
||||
<?= lang('Person.episode_form.title') ?> (<?= count($episode->persons) ?>)
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('headerRight') ?>
|
||||
@ -25,7 +25,6 @@
|
||||
]) ?>
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<?php if ($episodePersons): ?>
|
||||
|
||||
<?= form_section(
|
||||
lang('Person.episode_form.manage_section_title'),
|
||||
@ -37,42 +36,45 @@
|
||||
[
|
||||
[
|
||||
'header' => lang('Person.episode_form.person'),
|
||||
'cell' => function ($episodePerson) {
|
||||
'cell' => function ($person) {
|
||||
return '<div class="flex">' .
|
||||
'<a href="' .
|
||||
route_to('person-view', $episodePerson->person->id) .
|
||||
"\"><img src=\"{$episodePerson->person->image->thumbnail_url}\" alt=\"{$episodePerson->person->full_name}\" class=\"object-cover w-16 h-16 rounded-full\" /></a>" .
|
||||
route_to('person-view', $person->id) .
|
||||
"\"><img src=\"{$person->image->thumbnail_url}\" alt=\"{$person->full_name}\" class=\"object-cover w-16 h-16 rounded-full\" /></a>" .
|
||||
'<div class="flex flex-col ml-3">' .
|
||||
$episodePerson->person->full_name .
|
||||
($episodePerson->person_group && $episodePerson->person_role
|
||||
? '<span class="text-sm text-gray-600">' .
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$episodePerson->person_group}.label",
|
||||
) .
|
||||
' ▸ ' .
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$episodePerson->person_group}.roles.{$episodePerson->person_role}.label",
|
||||
) .
|
||||
'</span>'
|
||||
: '') .
|
||||
(empty($episodePerson->person->information_url)
|
||||
$person->full_name .
|
||||
implode(
|
||||
'',
|
||||
array_map(function ($role) {
|
||||
return '<span class="text-sm text-gray-600">' .
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$role->group}.label",
|
||||
) .
|
||||
' › ' .
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label",
|
||||
) .
|
||||
'</span>';
|
||||
}, $person->roles),
|
||||
) .
|
||||
($person->information_url === null
|
||||
? ''
|
||||
: "<a href=\"{$episodePerson->person->information_url}\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"text-sm text-blue-800 hover:underline\">" .
|
||||
$episodePerson->person->information_url .
|
||||
: "<a href=\"{$person->information_url}\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"text-sm text-blue-800 hover:underline\">" .
|
||||
$person->information_url .
|
||||
'</a>') .
|
||||
'</div></div>';
|
||||
},
|
||||
],
|
||||
[
|
||||
'header' => lang('Common.actions'),
|
||||
'cell' => function ($episodePerson): string {
|
||||
'cell' => function ($person): string {
|
||||
return button(
|
||||
lang('Person.episode_form.remove'),
|
||||
route_to(
|
||||
'episode-person-remove',
|
||||
$episodePerson->podcast_id,
|
||||
$episodePerson->episode_id,
|
||||
$episodePerson->id,
|
||||
$person->podcast_id,
|
||||
$person->episode_id,
|
||||
$person->id,
|
||||
),
|
||||
[
|
||||
'variant' => 'danger',
|
||||
@ -82,11 +84,10 @@
|
||||
},
|
||||
],
|
||||
],
|
||||
$episodePersons,
|
||||
$episode->persons,
|
||||
) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?= form_section(
|
||||
@ -117,10 +118,7 @@
|
||||
'person_group_role[]',
|
||||
$taxonomyOptions,
|
||||
old('person_group_role', []),
|
||||
[
|
||||
'id' => 'person_group_role',
|
||||
'class' => 'form-select mb-4',
|
||||
],
|
||||
['id' => 'person_group_role', 'class' => 'form-select mb-4'],
|
||||
) ?>
|
||||
|
||||
|
@ -53,34 +53,40 @@
|
||||
<tr>
|
||||
<td class="px-1 py-2 font-medium bg-white border border-light-blue-500"><?= form_input(
|
||||
[
|
||||
'id' => "soundbites_array[{$soundbite->id}][start_time]",
|
||||
'name' => "soundbites_array[{$soundbite->id}][start_time]",
|
||||
'type' => 'number',
|
||||
'min' => 0,
|
||||
'max' => $episode->audio_file_duration,
|
||||
'step' => 'any',
|
||||
'id' => "soundbites[{$soundbite->id}][start_time]",
|
||||
'name' => "soundbites[{$soundbite->id}][start_time]",
|
||||
'class' => 'form-input w-full border-none text-center',
|
||||
'value' => $soundbite->start_time,
|
||||
'data-type' => 'soundbite-field',
|
||||
'data-field-type' => 'start-time',
|
||||
'data-soundbite-id' => $soundbite->id,
|
||||
'required' => 'required',
|
||||
'min' => '0',
|
||||
],
|
||||
) ?></td>
|
||||
<td class="px-1 py-2 font-medium bg-white border border-light-blue-500"><?= form_input(
|
||||
[
|
||||
'id' => "soundbites_array[{$soundbite->id}][duration]",
|
||||
'name' => "soundbites_array[{$soundbite->id}][duration]",
|
||||
'type' => 'number',
|
||||
'min' => 0,
|
||||
'max' => $episode->audio_file_duration,
|
||||
'step' => 'any',
|
||||
'id' => "soundbites[{$soundbite->id}][duration]",
|
||||
'name' => "soundbites[{$soundbite->id}][duration]",
|
||||
'class' => 'form-input w-full border-none text-center',
|
||||
'value' => $soundbite->duration,
|
||||
'data-type' => 'soundbite-field',
|
||||
'data-field-type' => 'duration',
|
||||
'data-soundbite-id' => $soundbite->id,
|
||||
'required' => 'required',
|
||||
'min' => '0',
|
||||
],
|
||||
) ?></td>
|
||||
<td class="px-1 py-2 font-medium bg-white border border-light-blue-500"><?= form_input(
|
||||
[
|
||||
'id' => "soundbites_array[{$soundbite->id}][label]",
|
||||
'name' => "soundbites_array[{$soundbite->id}][label]",
|
||||
'id' => "soundbites[{$soundbite->id}][label]",
|
||||
'name' => "soundbites[{$soundbite->id}][label]",
|
||||
'class' => 'form-input w-full border-none',
|
||||
'value' => $soundbite->label,
|
||||
],
|
||||
@ -116,20 +122,27 @@
|
||||
<tr>
|
||||
<td class="px-1 py-4 font-medium bg-white border border-light-blue-500"><?= form_input(
|
||||
[
|
||||
'id' => 'soundbites_array[0][start_time]',
|
||||
'name' => 'soundbites_array[0][start_time]',
|
||||
'type' => 'number',
|
||||
'min' => 0,
|
||||
'max' => $episode->audio_file_duration,
|
||||
'step' => 'any',
|
||||
'id' => 'soundbites[0][start_time]',
|
||||
'name' => 'soundbites[0][start_time]',
|
||||
'class' => 'form-input w-full border-none text-center',
|
||||
'value' => old('start_time'),
|
||||
'data-soundbite-id' => '0',
|
||||
'data-type' => 'soundbite-field',
|
||||
'data-field-type' => 'start-time',
|
||||
'min' => '0',
|
||||
],
|
||||
) ?></td>
|
||||
<td class="px-1 py-4 font-medium bg-white border border-light-blue-500"><?= form_input(
|
||||
[
|
||||
'id' => 'soundbites_array[0][duration]',
|
||||
'name' => 'soundbites_array[0][duration]',
|
||||
'type' => 'number',
|
||||
'min' => 0,
|
||||
'max' => $episode->audio_file_duration,
|
||||
'step' => 'any',
|
||||
'id' => 'soundbites[0][duration]',
|
||||
'name' => 'soundbites[0][duration]',
|
||||
'class' => 'form-input w-full border-none text-center',
|
||||
'value' => old('duration'),
|
||||
'data-soundbite-id' => '0',
|
||||
@ -140,8 +153,8 @@
|
||||
) ?></td>
|
||||
<td class="px-1 py-4 font-medium bg-white border border-light-blue-500"><?= form_input(
|
||||
[
|
||||
'id' => 'soundbites_array[0][label]',
|
||||
'name' => 'soundbites_array[0][label]',
|
||||
'id' => 'soundbites[0][label]',
|
||||
'name' => 'soundbites[0][label]',
|
||||
'class' => 'form-input w-full border-none',
|
||||
'value' => old('label'),
|
||||
],
|
||||
@ -149,7 +162,7 @@
|
||||
<td class="px-4 py-2"><?= icon_button(
|
||||
'play',
|
||||
lang('Episode.soundbites_form.play'),
|
||||
null,
|
||||
'',
|
||||
['variant' => 'primary'],
|
||||
[
|
||||
'data-type' => 'play-soundbite',
|
||||
@ -170,13 +183,12 @@
|
||||
</td><td class="px-4 py-2"><?= icon_button(
|
||||
'timer',
|
||||
lang('Episode.soundbites_form.bookmark'),
|
||||
null,
|
||||
'',
|
||||
['variant' => 'info'],
|
||||
[
|
||||
'data-type' => 'get-soundbite',
|
||||
'data-start-time-field-name' =>
|
||||
'soundbites_array[0][start_time]',
|
||||
'data-duration-field-name' => 'soundbites_array[0][duration]',
|
||||
'data-start-time-field-name' => 'soundbites[0][start_time]',
|
||||
'data-duration-field-name' => 'soundbites[0][duration]',
|
||||
],
|
||||
) ?></td></tr>
|
||||
</tbody>
|
||||
|
@ -1,135 +0,0 @@
|
||||
<?= $this->extend('admin/_layout') ?>
|
||||
|
||||
<?= $this->section('title') ?>
|
||||
<?= lang('Person.podcast_form.title') ?>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('pageTitle') ?>
|
||||
<?= lang('Person.podcast_form.title') ?> (<?= count($podcastPersons) ?>)
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('headerRight') ?>
|
||||
<?= button(
|
||||
lang('Person.create'),
|
||||
route_to('person-create'),
|
||||
['variant' => 'primary', 'iconLeft' => 'add'],
|
||||
['class' => 'mr-2'],
|
||||
) ?>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?= form_open(route_to('podcast-person-edit', $podcast->id), [
|
||||
'method' => 'post',
|
||||
'class' => 'flex flex-col',
|
||||
]) ?>
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<?php if ($podcastPersons): ?>
|
||||
|
||||
<?= form_section(
|
||||
lang('Person.podcast_form.manage_section_title'),
|
||||
lang('Person.podcast_form.manage_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
|
||||
<?= data_table(
|
||||
[
|
||||
[
|
||||
'header' => lang('Person.podcast_form.person'),
|
||||
'cell' => function ($podcastPerson) {
|
||||
return '<div class="flex">' .
|
||||
'<a href="' .
|
||||
route_to('person-view', $podcastPerson->person->id) .
|
||||
"\"><img src=\"{$podcastPerson->person->image->thumbnail_url}\" alt=\"{$podcastPerson->person->full_name}\" class=\"object-cover w-16 h-16 rounded-full\" /></a>" .
|
||||
'<div class="flex flex-col ml-3">' .
|
||||
$podcastPerson->person->full_name .
|
||||
($podcastPerson->person_group &&
|
||||
$podcastPerson->person_role
|
||||
? '<span class="text-sm text-gray-600">' .
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$podcastPerson->person_group}.label",
|
||||
) .
|
||||
' ▸ ' .
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$podcastPerson->person_group}.roles.{$podcastPerson->person_role}.label",
|
||||
) .
|
||||
'</span>'
|
||||
: '') .
|
||||
(empty($podcastPerson->person->information_url)
|
||||
? ''
|
||||
: "<a href=\"{$podcastPerson->person->information_url}\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"text-sm text-blue-800 hover:underline\">" .
|
||||
$podcastPerson->person->information_url .
|
||||
'</a>') .
|
||||
'</div></div>';
|
||||
},
|
||||
],
|
||||
[
|
||||
'header' => lang('Common.actions'),
|
||||
'cell' => function ($podcastPerson): string {
|
||||
return button(
|
||||
lang('Person.podcast_form.remove'),
|
||||
route_to(
|
||||
'podcast-person-remove',
|
||||
$podcastPerson->podcast_id,
|
||||
$podcastPerson->id,
|
||||
),
|
||||
[
|
||||
'variant' => 'danger',
|
||||
'size' => 'small',
|
||||
],
|
||||
);
|
||||
},
|
||||
],
|
||||
],
|
||||
$podcastPersons,
|
||||
) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?= form_section(
|
||||
lang('Person.podcast_form.add_section_title'),
|
||||
lang('Person.podcast_form.add_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Person.podcast_form.person'),
|
||||
'person',
|
||||
[],
|
||||
lang('Person.podcast_form.person_hint'),
|
||||
) ?>
|
||||
<?= form_multiselect('person[]', $personOptions, old('person', []), [
|
||||
'id' => 'person',
|
||||
'class' => 'form-select mb-4',
|
||||
'required' => 'required',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Person.podcast_form.group_role'),
|
||||
'group_role',
|
||||
[],
|
||||
lang('Person.podcast_form.group_role_hint'),
|
||||
true,
|
||||
) ?>
|
||||
<?= form_multiselect(
|
||||
'person_group_role[]',
|
||||
$taxonomyOptions,
|
||||
old('person_group_role', []),
|
||||
[
|
||||
'id' => 'person_group_role',
|
||||
'class' => 'form-select mb-4',
|
||||
],
|
||||
) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
<?= button(
|
||||
lang('Person.podcast_form.submit_add'),
|
||||
'',
|
||||
['variant' => 'primary'],
|
||||
['type' => 'submit', 'class' => 'self-end'],
|
||||
) ?>
|
||||
<?= form_close() ?>
|
||||
|
||||
<?= $this->endSection() ?>
|
129
app/Views/admin/podcast/persons.php
Normal file
129
app/Views/admin/podcast/persons.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?= $this->extend('admin/_layout') ?>
|
||||
|
||||
<?= $this->section('title') ?>
|
||||
<?= lang('Person.podcast_form.title') ?>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('pageTitle') ?>
|
||||
<?= lang('Person.podcast_form.title') ?> (<?= count($podcast->persons) ?>)
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('headerRight') ?>
|
||||
<?= button(
|
||||
lang('Person.create'),
|
||||
route_to('person-create'),
|
||||
['variant' => 'primary', 'iconLeft' => 'add'],
|
||||
['class' => 'mr-2'],
|
||||
) ?>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?= form_open(route_to('podcast-person-edit', $podcast->id), [
|
||||
'method' => 'post',
|
||||
'class' => 'flex flex-col',
|
||||
]) ?>
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<?= form_section(
|
||||
lang('Person.podcast_form.manage_section_title'),
|
||||
lang('Person.podcast_form.manage_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
|
||||
<?= data_table(
|
||||
[
|
||||
[
|
||||
'header' => lang('Person.podcast_form.person'),
|
||||
'cell' => function ($person) {
|
||||
return '<div class="flex">' .
|
||||
'<a href="' .
|
||||
route_to('person-view', $person->id) .
|
||||
"\"><img src=\"{$person->image->thumbnail_url}\" alt=\"{$person->full_name}\" class=\"object-cover w-16 h-16 rounded-full\" /></a>" .
|
||||
'<div class="flex flex-col ml-3">' .
|
||||
$person->full_name .
|
||||
implode(
|
||||
'',
|
||||
array_map(function ($role) {
|
||||
return '<span class="text-sm text-gray-600">' .
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$role->group}.label",
|
||||
) .
|
||||
' › ' .
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label",
|
||||
) .
|
||||
'</span>';
|
||||
}, $person->roles),
|
||||
) .
|
||||
($person->information_url === null
|
||||
? ''
|
||||
: "<a href=\"{$person->information_url}\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"text-sm text-blue-800 hover:underline\">" .
|
||||
$person->information_url .
|
||||
'</a>') .
|
||||
'</div></div>';
|
||||
},
|
||||
],
|
||||
[
|
||||
'header' => lang('Common.actions'),
|
||||
'cell' => function ($person): string {
|
||||
return button(
|
||||
lang('Person.podcast_form.remove'),
|
||||
route_to(
|
||||
'podcast-person-remove',
|
||||
$person->podcast_id,
|
||||
$person->id,
|
||||
),
|
||||
[
|
||||
'variant' => 'danger',
|
||||
'size' => 'small',
|
||||
],
|
||||
);
|
||||
},
|
||||
],
|
||||
],
|
||||
$podcast->persons,
|
||||
) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
|
||||
|
||||
<?= form_section(
|
||||
lang('Person.podcast_form.add_section_title'),
|
||||
lang('Person.podcast_form.add_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Person.podcast_form.person'),
|
||||
'person',
|
||||
[],
|
||||
lang('Person.podcast_form.person_hint'),
|
||||
) ?>
|
||||
<?= form_multiselect('persons[]', $personOptions, old('persons', []), [
|
||||
'id' => 'persons',
|
||||
'class' => 'form-select mb-4',
|
||||
'required' => 'required',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Person.podcast_form.roles'),
|
||||
'roles',
|
||||
[],
|
||||
lang('Person.podcast_form.roles_hint'),
|
||||
true,
|
||||
) ?>
|
||||
<?= form_multiselect('roles[]', $taxonomyOptions, old('roles', []), [
|
||||
'id' => 'roles',
|
||||
'class' => 'form-select mb-4',
|
||||
]) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
<?= button(
|
||||
lang('Person.podcast_form.submit_add'),
|
||||
'',
|
||||
['variant' => 'primary'],
|
||||
['type' => 'submit', 'class' => 'self-end'],
|
||||
) ?>
|
||||
<?= form_close() ?>
|
||||
|
||||
<?= $this->endSection() ?>
|
@ -3,7 +3,7 @@
|
||||
use Config\Services;
|
||||
use CodeIgniter\CodeIgniter;
|
||||
|
||||
$error_id = uniqid('error', true);
|
||||
$errorId = uniqid('error', true);
|
||||
?>
|
||||
<!doctype html>
|
||||
<html>
|
||||
@ -103,12 +103,12 @@ $error_id = uniqid('error', true);
|
||||
$row['class'] . $row['type'] . $row['function'],
|
||||
) ?>
|
||||
<?php if (!empty($row['args'])): ?>
|
||||
<?php $args_id = $error_id . 'args' . $index; ?>
|
||||
<?php $argsId = $errorId . 'args' . $index; ?>
|
||||
( <a href="#" onclick="return toggle('<?= esc(
|
||||
$args_id,
|
||||
$argsId,
|
||||
'attr',
|
||||
) ?>');">arguments</a> )
|
||||
<div class="args" id="<?= esc($args_id, 'attr') ?>">
|
||||
<div class="args" id="<?= esc($argsId, 'attr') ?>">
|
||||
<table cellspacing="0">
|
||||
|
||||
<?php
|
||||
|
@ -27,7 +27,7 @@
|
||||
'text-2xl inline-flex items-baseline font-bold font-display',
|
||||
],
|
||||
) ?>
|
||||
<?php if (user()->podcasts): ?>
|
||||
<?php if (user()->podcasts !== []): ?>
|
||||
<button type="button" class="inline-flex items-center px-6 py-2 mt-auto font-semibold outline-none focus:ring" id="interact-as-dropdown" data-dropdown="button" data-dropdown-target="interact-as-dropdown-menu" aria-haspopup="true" aria-expanded="false">
|
||||
<img src="<?= interact_as_actor()
|
||||
->avatar_image_url ?>" class="w-8 h-8 mr-2 rounded-full" />
|
||||
|
@ -42,37 +42,7 @@
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if (!empty($persons)): ?>
|
||||
<div class="flex w-full mb-6 space-x-2 overflow-y-auto">
|
||||
<?php foreach ($persons as $person): ?>
|
||||
<?php if ($person['information_url']): ?>
|
||||
<a href="<?= $person[
|
||||
'information_url'
|
||||
] ?>" target="_blank" rel="noreferrer noopener" class="flex-shrink-0">
|
||||
<img
|
||||
src="<?= $person['thumbnail_url'] ?>"
|
||||
alt="<?= $person['full_name'] ?>"
|
||||
class="object-cover w-12 h-12 rounded-full"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
title="[<?= $person['full_name'] ?>] <?= $person[
|
||||
'roles'
|
||||
] ?>" />
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<img
|
||||
src="<?= $person['thumbnail_url'] ?>"
|
||||
alt="<?= $person['full_name'] ?>"
|
||||
class="object-cover w-12 h-12 rounded-full"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
title="[<?= $person['full_name'] ?>] <?= $person[
|
||||
'roles'
|
||||
] ?>" />
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?= person_list($podcast->persons, 'mb-6') ?>
|
||||
<div class="space-x-4">
|
||||
<a href="#" class="hover:underline"><?= lang('Podcast.followers', [
|
||||
'numberOfFollowers' => $podcast->actor->followers_count,
|
||||
|
@ -111,37 +111,8 @@
|
||||
],
|
||||
) ?>
|
||||
</div>
|
||||
<?php if ($episode->location !== null): ?>
|
||||
<?= location_link($episode->location, 'text-sm mb-4') ?>
|
||||
<?php endif; ?>
|
||||
<?php if ($episodePersons): ?>
|
||||
<div class="flex w-full space-x-2 overflow-y-auto">
|
||||
<?php foreach ($episodePersons as $person): ?>
|
||||
<?php if ($person['information_url']): ?>
|
||||
<a href="<?= $person[
|
||||
'information_url'
|
||||
] ?>" target="_blank" rel="noreferrer noopener" class="flex-shrink-0">
|
||||
<img src="<?= $person[
|
||||
'thumbnail_url'
|
||||
] ?>" alt="<?= $person[
|
||||
'full_name'
|
||||
] ?>" class="object-cover w-12 h-12 rounded-full" data-toggle="tooltip"
|
||||
data-placement="bottom" title="[<?= $person['full_name'] ?>] <?= $person[
|
||||
'roles'
|
||||
] ?>" /></a>
|
||||
<?php else: ?>
|
||||
<img src="<?= $person[
|
||||
'thumbnail_url'
|
||||
] ?>" alt="<?= $person[
|
||||
'full_name'
|
||||
] ?>" class="object-cover w-12 h-12 rounded-full" data-toggle="tooltip"
|
||||
data-placement="bottom" title="[<?= $person['full_name'] ?>] <?= $person[
|
||||
'roles'
|
||||
] ?>" />
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?= location_link($episode->location, 'text-sm mb-4') ?>
|
||||
<?= person_list($episode->persons) ?>
|
||||
</div>
|
||||
</div>
|
||||
<audio controls preload="none" class="w-full mt-auto">
|
||||
|
Loading…
x
Reference in New Issue
Block a user