Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • adaures/castopod
  • mkljczk/castopod-host
  • spaetz/castopod-host
  • PatrykMis/castopod
  • jonas/castopod
  • ajeremias/castopod
  • misuzu/castopod
  • KrzysztofDomanczyk/castopod
  • Behel/castopod
  • nebulon/castopod
  • ewen/castopod
  • NeoluxConsulting/castopod
  • nateritter/castopod-og
  • prcutler/castopod
14 results
Show changes
Showing
with 2007 additions and 1623 deletions
<?php
declare(strict_types=1);
/**
* Class FakePodcastsAnalyticsSeeder
* Inserts Fake Analytics in the database
* Class FakePodcastsAnalyticsSeeder Inserts Fake Analytics in the database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Seeds;
use App\Models\PodcastModel;
use App\Entities\Episode;
use App\Entities\Podcast;
use App\Models\EpisodeModel;
use App\Models\PodcastModel;
use CodeIgniter\Database\Seeder;
use Exception;
use GeoIp2\Database\Reader;
use GeoIp2\Exception\AddressNotFoundException;
use Override;
class FakePodcastsAnalyticsSeeder extends Seeder
{
public function run()
#[Override]
public function run(): void
{
$podcast = (new PodcastModel())->first();
$jsonUserAgents = json_decode(
file_get_contents(
'https://raw.githubusercontent.com/opawg/user-agents/master/src/user-agents.json',
),
file_get_contents('https://raw.githubusercontent.com/opawg/user-agents/master/src/user-agents.json'),
true,
512,
JSON_THROW_ON_ERROR,
);
$jsonRSSUserAgents = json_decode(
......@@ -34,170 +39,168 @@ class FakePodcastsAnalyticsSeeder extends Seeder
'https://raw.githubusercontent.com/opawg/podcast-rss-useragents/master/src/rss-ua.json',
),
true,
512,
JSON_THROW_ON_ERROR,
);
if ($podcast) {
$firstEpisode = (new EpisodeModel())
->selectMin('published_at')
->first();
for (
$date = strtotime($firstEpisode->published_at);
$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 = [];
$episodes = (new EpisodeModel())
->where([
'podcast_id' => $podcast->id,
'DATE(published_at) <=' => date('Y-m-d', $date),
])
->findAll();
foreach ($episodes as $episode) {
$age = floor(
($date - strtotime($episode->published_at)) / 86400,
);
$proba1 = floor(exp(3 - $age / 40)) + 1;
for (
$num_line = 0;
$num_line < rand(1, $proba1);
$num_line++
) {
$proba2 = floor(exp(6 - $age / 20)) + 10;
$player =
$jsonUserAgents[
rand(1, count($jsonUserAgents) - 1)
];
$service =
$jsonRSSUserAgents[
rand(1, count($jsonRSSUserAgents) - 1)
]['slug'];
$app = isset($player['app']) ? $player['app'] : '';
$device = isset($player['device'])
? $player['device']
: '';
$os = isset($player['os']) ? $player['os'] : '';
$isBot = isset($player['bot']) ? $player['bot'] : 0;
$fakeIp =
rand(0, 255) .
'.' .
rand(0, 255) .
'.' .
rand(0, 255) .
'.' .
rand(0, 255);
$cityReader = new \GeoIp2\Database\Reader(
WRITEPATH .
'uploads/GeoLite2-City/GeoLite2-City.mmdb',
);
$countryCode = 'N/A';
$regionCode = 'N/A';
$latitude = null;
$longitude = null;
try {
$city = $cityReader->city($fakeIp);
$countryCode = empty($city->country->isoCode)
? 'N/A'
: $city->country->isoCode;
$regionCode = empty($city->subdivisions[0]->isoCode)
? 'N/A'
: $city->subdivisions[0]->isoCode;
$latitude = round($city->location->latitude, 3);
$longitude = round($city->location->longitude, 3);
} catch (\GeoIp2\Exception\AddressNotFoundException $ex) {
//Bad luck, bad IP, nothing to do.
}
$hits = rand(0, $proba2);
$analytics_podcasts[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'duration' => rand(60, 3600),
'bandwidth' => rand(1000000, 10000000),
'hits' => $hits,
'unique_listeners' => $hits,
];
$analytics_podcasts_by_hour[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'hour' => rand(0, 23),
'hits' => $hits,
];
$analytics_podcasts_by_country[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'country_code' => $countryCode,
'hits' => $hits,
];
$analytics_podcasts_by_episode[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'episode_id' => $episode->id,
'age' => $age,
'hits' => $hits,
];
$analytics_podcasts_by_player[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'service' => $service,
'app' => $app,
'device' => $device,
'os' => $os,
'is_bot' => $isBot,
'hits' => $hits,
];
$analytics_podcasts_by_region[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'country_code' => $countryCode,
'region_code' => $regionCode,
'latitude' => $latitude,
'longitude' => $longitude,
'hits' => $hits,
$podcast = (new PodcastModel())->first();
if (! $podcast instanceof Podcast) {
throw new Exception("COULD NOT POPULATE DATABASE:\n\tCreate a podcast with episodes first.\n");
}
$firstEpisode = (new EpisodeModel())
->selectMin('published_at')
->first();
if (! $firstEpisode instanceof Episode) {
throw new Exception("COULD NOT POPULATE DATABASE:\n\tCreate an episode first.");
}
for (
$date = strtotime((string) $firstEpisode->published_at);
$date < strtotime('now');
$date = strtotime(date('Y-m-d', $date) . ' +1 day')
) {
$analyticsPodcasts = [];
$analyticsPodcastsByHour = [];
$analyticsPodcastsByCountry = [];
$analyticsPodcastsByEpisode = [];
$analyticsPodcastsByPlayer = [];
$analyticsPodcastsByRegion = [];
$episodes = (new EpisodeModel())
->where('podcast_id', $podcast->id)
->where('`published_at` <= UTC_TIMESTAMP()', null, false)
->findAll();
foreach ($episodes as $episode) {
$age = floor(($date - strtotime((string) $episode->published_at)) / 86400);
$probability1 = floor(exp(3 - $age / 40)) + 1;
for (
$lineNumber = 0;
$lineNumber < random_int(1, (int) $probability1);
++$lineNumber
) {
$probability2 = floor(exp(6 - $age / 20)) + 10;
$player =
$jsonUserAgents[
random_int(1, count($jsonUserAgents) - 1)
];
$service =
$jsonRSSUserAgents[
random_int(1, count($jsonRSSUserAgents) - 1)
]['slug'];
$app = $player['app'] ?? '';
$device = $player['device'] ?? '';
$os = $player['os'] ?? '';
$isBot = $player['bot'] ?? 0;
$fakeIp =
random_int(0, 255) .
'.' .
random_int(0, 255) .
'.' .
random_int(0, 255) .
'.' .
random_int(0, 255);
$cityReader = new Reader(WRITEPATH . 'uploads/GeoLite2-City/GeoLite2-City.mmdb');
$countryCode = 'N/A';
$regionCode = 'N/A';
$latitude = null;
$longitude = null;
try {
$city = $cityReader->city($fakeIp);
$countryCode = $city->country->isoCode ?? 'N/A';
$regionCode = $city->subdivisions === []
? 'N/A'
: $city->subdivisions[0]->isoCode;
$latitude = round((float) $city->location->latitude, 3);
$longitude = round((float) $city->location->longitude, 3);
} catch (AddressNotFoundException) {
//Bad luck, bad IP, nothing to do.
}
$hits = random_int(0, (int) $probability2);
$analyticsPodcasts[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'duration' => random_int(60, 3600),
'bandwidth' => random_int(1000000, 10000000),
'hits' => $hits,
'unique_listeners' => $hits,
];
$analyticsPodcastsByHour[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'hour' => random_int(0, 23),
'hits' => $hits,
];
$analyticsPodcastsByCountry[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'country_code' => $countryCode,
'hits' => $hits,
];
$analyticsPodcastsByEpisode[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'episode_id' => $episode->id,
'age' => $age,
'hits' => $hits,
];
$analyticsPodcastsByPlayer[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'service' => $service,
'app' => $app,
'device' => $device,
'os' => $os,
'is_bot' => $isBot,
'hits' => $hits,
];
$analyticsPodcastsByRegion[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'country_code' => $countryCode,
'region_code' => $regionCode,
'latitude' => $latitude,
'longitude' => $longitude,
'hits' => $hits,
];
}
$this->db
->table('analytics_podcasts')
->ignore(true)
->insertBatch($analytics_podcasts);
$this->db
->table('analytics_podcasts_by_hour')
->ignore(true)
->insertBatch($analytics_podcasts_by_hour);
$this->db
->table('analytics_podcasts_by_country')
->ignore(true)
->insertBatch($analytics_podcasts_by_country);
$this->db
->table('analytics_podcasts_by_episode')
->ignore(true)
->insertBatch($analytics_podcasts_by_episode);
$this->db
->table('analytics_podcasts_by_player')
->ignore(true)
->insertBatch($analytics_podcasts_by_player);
$this->db
->table('analytics_podcasts_by_region')
->ignore(true)
->insertBatch($analytics_podcasts_by_region);
}
} else {
echo "COULD NOT POPULATE DATABASE:\n\tCreate a podcast with episodes first.\n";
$this->db
->table('analytics_podcasts')
->ignore(true)
->insertBatch($analyticsPodcasts);
$this->db
->table('analytics_podcasts_by_hour')
->ignore(true)
->insertBatch($analyticsPodcastsByHour);
$this->db
->table('analytics_podcasts_by_country')
->ignore(true)
->insertBatch($analyticsPodcastsByCountry);
$this->db
->table('analytics_podcasts_by_episode')
->ignore(true)
->insertBatch($analyticsPodcastsByEpisode);
$this->db
->table('analytics_podcasts_by_player')
->ignore(true)
->insertBatch($analyticsPodcastsByPlayer);
$this->db
->table('analytics_podcasts_by_region')
->ignore(true)
->insertBatch($analyticsPodcastsByRegion);
}
}
}
<?php
declare(strict_types=1);
/**
* Class FakeWebsiteAnalyticsSeeder
* Inserts Fake Analytics in the database
* Class FakeWebsiteAnalyticsSeeder Inserts Fake Analytics in the database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Seeds;
use App\Models\PodcastModel;
use App\Entities\Episode;
use App\Entities\Podcast;
use App\Models\EpisodeModel;
use App\Models\PodcastModel;
use CodeIgniter\Database\Seeder;
use Exception;
use Override;
class FakeWebsiteAnalyticsSeeder extends Seeder
{
protected $keywords = [
/**
* @var string[]
*/
protected array $keywords = [
'all the smoke podcast',
'apple podcast',
'bad friends podcast',
......@@ -70,7 +77,11 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
'wind of change podcast',
'your own backyard podcast',
];
protected $domains = [
/**
* @var string[]
*/
protected array $domains = [
'360.cn ',
'adobe.com ',
'aliexpress.com ',
......@@ -123,7 +134,10 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
'zoom.us ',
];
protected $browsers = [
/**
* @var string[]
*/
protected array $browsers = [
'Android Browser',
'Avast Secure Browser',
'BlackBerry Browser',
......@@ -168,94 +182,95 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
'WOSBrowser',
];
public function run()
#[Override]
public function run(): void
{
$podcast = (new PodcastModel())->first();
if ($podcast) {
$firstEpisode = (new EpisodeModel())
->selectMin('published_at')
->first();
if (! $podcast instanceof Podcast) {
throw new Exception("COULD NOT POPULATE DATABASE:\n\tCreate a podcast with episodes first.\n");
}
for (
$date = strtotime($firstEpisode->published_at);
$date < strtotime('now');
$date = strtotime(date('Y-m-d', $date) . ' +1 day')
) {
$website_by_browser = [];
$website_by_entry_page = [];
$website_by_referer = [];
$firstEpisode = (new EpisodeModel())
->selectMin('published_at')
->first();
$episodes = (new EpisodeModel())
->where([
'podcast_id' => $podcast->id,
'DATE(published_at) <=' => date('Y-m-d', $date),
])
->findAll();
foreach ($episodes as $episode) {
$age = floor(
($date - strtotime($episode->published_at)) / 86400,
);
$proba1 = floor(exp(3 - $age / 40)) + 1;
if (! $firstEpisode instanceof Episode) {
throw new Exception("COULD NOT POPULATE DATABASE:\n\tCreate an episode first.");
}
for (
$num_line = 0;
$num_line < rand(1, $proba1);
$num_line++
) {
$proba2 = floor(exp(6 - $age / 20)) + 10;
for (
$date = strtotime((string) $firstEpisode->published_at);
$date < strtotime('now');
$date = strtotime(date('Y-m-d', $date) . ' +1 day')
) {
$websiteByBrowser = [];
$websiteByEntryPage = [];
$websiteByReferer = [];
$domain =
$this->domains[rand(0, count($this->domains) - 1)];
$keyword =
$this->keywords[
rand(0, count($this->keywords) - 1)
];
$browser =
$this->browsers[
rand(0, count($this->browsers) - 1)
];
$episodes = (new EpisodeModel())
->where('podcast_id', $podcast->id)
->where('`published_at` <= UTC_TIMESTAMP()', null, false)
->findAll();
foreach ($episodes as $episode) {
$age = floor(($date - strtotime((string) $episode->published_at)) / 86400);
$probability1 = (int) floor(exp(3 - $age / 40)) + 1;
$hits = rand(0, $proba2);
for (
$lineNumber = 0;
$lineNumber < random_int(1, $probability1);
++$lineNumber
) {
$probability2 = (int) floor(exp(6 - $age / 20)) + 10;
$website_by_browser[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'browser' => $browser,
'hits' => $hits,
];
$website_by_entry_page[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'entry_page_url' => $episode->link,
'hits' => $hits,
$domain =
$this->domains[random_int(0, count($this->domains) - 1)];
$keyword =
$this->keywords[
random_int(0, count($this->keywords) - 1)
];
$website_by_referer[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'referer_url' =>
'http://' . $domain . '/?q=' . $keyword,
'domain' => $domain,
'keywords' => $keyword,
'hits' => $hits,
$browser =
$this->browsers[
random_int(0, count($this->browsers) - 1)
];
}
$hits = random_int(0, $probability2);
$websiteByBrowser[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'browser' => $browser,
'hits' => $hits,
];
$websiteByEntryPage[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'entry_page_url' => $episode->link,
'hits' => $hits,
];
$websiteByReferer[] = [
'podcast_id' => $podcast->id,
'date' => date('Y-m-d', $date),
'referer_url' => 'http://' . $domain . '/?q=' . $keyword,
'domain' => $domain,
'keywords' => $keyword,
'hits' => $hits,
];
}
$this->db
->table('analytics_website_by_browser')
->ignore(true)
->insertBatch($website_by_browser);
$this->db
->table('analytics_website_by_entry_page')
->ignore(true)
->insertBatch($website_by_entry_page);
$this->db
->table('analytics_website_by_referer')
->ignore(true)
->insertBatch($website_by_referer);
}
} else {
echo "COULD NOT POPULATE DATABASE:\n\tCreate a podcast with episodes first.\n";
$this->db
->table('analytics_website_by_browser')
->ignore(true)
->insertBatch($websiteByBrowser);
$this->db
->table('analytics_website_by_entry_page')
->ignore(true)
->insertBatch($websiteByEntryPage);
$this->db
->table('analytics_website_by_referer')
->ignore(true)
->insertBatch($websiteByReferer);
}
}
}
<?php
declare(strict_types=1);
/**
* Class LanguageSeeder
* Inserts values in languages table in database
* Class LanguageSeeder Inserts values in languages table in database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
/**
* From https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
* (cc) Creative Commons Attribution-ShareAlike 3.0
* From https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes (cc) Creative Commons Attribution-ShareAlike 3.0
* 2020-06-07
*/
namespace App\Database\Seeds;
use CodeIgniter\Database\Seeder;
use Override;
class LanguageSeeder extends Seeder
{
public function run()
#[Override]
public function run(): void
{
$data = [
['code' => 'aa', 'native_name' => 'Afaraf'],
[
'code' => 'ab',
'code' => 'aa',
'native_name' => 'Afaraf',
],
[
'code' => 'ab',
'native_name' => 'аҧсуа бызшәа, аҧсшәа',
],
['code' => 'ae', 'native_name' => 'avesta'],
[
'code' => 'af',
'code' => 'ae',
'native_name' => 'Avesta',
],
[
'code' => 'af',
'native_name' => 'Afrikaans',
],
['code' => 'ak', 'native_name' => 'Akan'],
['code' => 'am', 'native_name' => 'አማርኛ'],
[
'code' => 'an',
'native_name' => 'aragonés',
'code' => 'ak',
'native_name' => 'Akan',
],
[
'code' => 'am',
'native_name' => 'አማርኛ',
],
[
'code' => 'an',
'native_name' => 'Aragonés',
],
[
'code' => 'ar',
'native_name' => 'العربية',
],
[
'code' => 'as',
'native_name' => 'অসমীয়া',
],
['code' => 'ar', 'native_name' => 'العربية'],
['code' => 'as', 'native_name' => 'অসমীয়া'],
[
'code' => 'av',
'code' => 'av',
'native_name' => 'авар мацӀ, магӀарул мацӀ',
],
['code' => 'ay', 'native_name' => 'aymar aru'],
[
'code' => 'az',
'code' => 'ay',
'native_name' => 'Aymar aru',
],
[
'code' => 'az',
'native_name' => 'azərbaycan dili',
],
[
'code' => 'ba',
'code' => 'ba',
'native_name' => 'башҡорт теле',
],
[
'code' => 'be',
'code' => 'be',
'native_name' => 'беларуская мова',
],
[
'code' => 'bg',
'code' => 'bg',
'native_name' => 'български език',
],
[
'code' => 'bh',
'code' => 'bh',
'native_name' => 'भोजपुरी',
],
['code' => 'bi', 'native_name' => 'Bislama'],
[
'code' => 'bm',
'native_name' => 'bamanankan',
'code' => 'bi',
'native_name' => 'Bislama',
],
[
'code' => 'bm',
'native_name' => 'Bamanankan',
],
[
'code' => 'bn',
'native_name' => 'বাংলা',
],
[
'code' => 'bo',
'native_name' => 'བོད་ཡིག',
],
[
'code' => 'br',
'native_name' => 'Brezhoneg',
],
['code' => 'bn', 'native_name' => 'বাংলা'],
['code' => 'bo', 'native_name' => 'བོད་ཡིག'],
['code' => 'br', 'native_name' => 'brezhoneg'],
[
'code' => 'bs',
'native_name' => 'bosanski jezik',
'code' => 'bs',
'native_name' => 'Bosanski jezik',
],
[
'code' => 'ca',
'native_name' => 'català, valencià',
'code' => 'ca',
'native_name' => 'Català, valencià',
],
[
'code' => 'ce',
'code' => 'ce',
'native_name' => 'нохчийн мотт',
],
['code' => 'ch', 'native_name' => 'Chamoru'],
[
'code' => 'co',
'native_name' => 'corsu, lingua corsa',
'code' => 'ch',
'native_name' => 'Chamoru',
],
[
'code' => 'co',
'native_name' => 'Corsu, lingua corsa',
],
['code' => 'cr', 'native_name' => 'ᓀᐦᐃᔭᐍᐏᐣ'],
[
'code' => 'cs',
'code' => 'cr',
'native_name' => 'ᓀᐦᐃᔭᐍᐏᐣ',
],
[
'code' => 'cs',
'native_name' => 'čeština, český jazyk',
],
[
'code' => 'cu',
'code' => 'cu',
'native_name' => 'ѩзыкъ словѣньскъ',
],
[
'code' => 'cv',
'code' => 'cv',
'native_name' => 'чӑваш чӗлхи',
],
['code' => 'cy', 'native_name' => 'Cymraeg'],
['code' => 'da', 'native_name' => 'dansk'],
['code' => 'de', 'native_name' => 'Deutsch'],
[
'code' => 'dv',
'code' => 'cy',
'native_name' => 'Cymraeg',
],
[
'code' => 'da',
'native_name' => 'Dansk',
],
[
'code' => 'de',
'native_name' => 'Deutsch',
],
[
'code' => 'dv',
'native_name' => 'ދިވެހި',
],
['code' => 'dz', 'native_name' => 'རྫོང་ཁ'],
['code' => 'ee', 'native_name' => 'Eʋegbe'],
[
'code' => 'el',
'code' => 'dz',
'native_name' => 'རྫོང་ཁ',
],
[
'code' => 'ee',
'native_name' => 'Eʋegbe',
],
[
'code' => 'el',
'native_name' => 'ελληνικά',
],
['code' => 'en', 'native_name' => 'English'],
[
'code' => 'eo',
'code' => 'en',
'native_name' => 'English',
],
[
'code' => 'eo',
'native_name' => 'Esperanto',
],
[
'code' => 'es',
'code' => 'es',
'native_name' => 'Español',
],
[
'code' => 'et',
'code' => 'et',
'native_name' => 'eesti, eesti keel',
],
[
'code' => 'eu',
'native_name' => 'euskara, euskera',
'code' => 'eu',
'native_name' => 'Euskara, euskera',
],
[
'code' => 'fa',
'native_name' => 'فارسی',
],
['code' => 'fa', 'native_name' => 'فارسی'],
[
'code' => 'ff',
'code' => 'ff',
'native_name' => 'Fulfulde, Pulaar, Pular',
],
[
'code' => 'fi',
'native_name' => 'suomi, suomen kieli',
'code' => 'fi',
'native_name' => 'Suomi, suomen kieli',
],
[
'code' => 'fj',
'native_name' => 'Vosa Vakaviti',
],
[
'code' => 'fj',
'native_name' => 'vosa Vakaviti',
'code' => 'fo',
'native_name' => 'Føroyskt',
],
['code' => 'fo', 'native_name' => 'føroyskt'],
[
'code' => 'fr',
'native_name' => 'français, langue française',
'code' => 'fr',
'native_name' => 'Français, langue française',
],
[
'code' => 'fy',
'code' => 'fy',
'native_name' => 'Frysk',
],
['code' => 'ga', 'native_name' => 'Gaeilge'],
[
'code' => 'gd',
'code' => 'ga',
'native_name' => 'Gaeilge',
],
[
'code' => 'gd',
'native_name' => 'Gàidhlig',
],
['code' => 'gl', 'native_name' => 'Galego'],
['code' => 'gn', 'native_name' => 'Avañe\'ẽ'],
['code' => 'gu', 'native_name' => 'ગુજરાતી'],
[
'code' => 'gv',
'code' => 'gl',
'native_name' => 'Galego',
],
[
'code' => 'gn',
'native_name' => "Avañe'ẽ",
],
[
'code' => 'gu',
'native_name' => 'ગુજરાતી',
],
[
'code' => 'gv',
'native_name' => 'Gaelg, Gailck',
],
[
'code' => 'ha',
'code' => 'ha',
'native_name' => '(Hausa) هَوُسَ',
],
['code' => 'he', 'native_name' => 'עברית'],
[
'code' => 'hi',
'code' => 'he',
'native_name' => 'עברית',
],
[
'code' => 'hi',
'native_name' => 'हिन्दी, हिंदी',
],
[
'code' => 'ho',
'code' => 'ho',
'native_name' => 'Hiri Motu',
],
[
'code' => 'hr',
'native_name' => 'hrvatski jezik',
'code' => 'hr',
'native_name' => 'Hrvatski jezik',
],
[
'code' => 'ht',
'code' => 'ht',
'native_name' => 'Kreyòl ayisyen',
],
['code' => 'hu', 'native_name' => 'magyar'],
['code' => 'hy', 'native_name' => 'Հայերեն'],
['code' => 'hz', 'native_name' => 'Otjiherero'],
[
'code' => 'ia',
'code' => 'hu',
'native_name' => 'Magyar',
],
[
'code' => 'hy',
'native_name' => 'Հայերեն',
],
[
'code' => 'hz',
'native_name' => 'Otjiherero',
],
[
'code' => 'ia',
'native_name' => 'Interlingua',
],
[
'code' => 'id',
'code' => 'id',
'native_name' => 'Bahasa Indonesia',
],
[
'code' => 'ie',
'native_name' =>
'(originally:) Occidental, (after WWII:) Interlingue',
'code' => 'ie',
'native_name' => 'Interlingue, formerly Occidental',
],
[
'code' => 'ig',
'native_name' => 'Asụsụ Igbo',
],
['code' => 'ig', 'native_name' => 'Asụsụ Igbo'],
[
'code' => 'ii',
'code' => 'ii',
'native_name' => 'ꆈꌠ꒿ Nuosuhxop',
],
[
'code' => 'ik',
'code' => 'ik',
'native_name' => 'Iñupiaq, Iñupiatun',
],
['code' => 'io', 'native_name' => 'Ido'],
[
'code' => 'is',
'code' => 'io',
'native_name' => 'Ido',
],
[
'code' => 'is',
'native_name' => 'Íslenska',
],
['code' => 'it', 'native_name' => 'Italiano'],
['code' => 'iu', 'native_name' => 'ᐃᓄᒃᑎᑐᑦ'],
[
'code' => 'ja',
'code' => 'it',
'native_name' => 'Italiano',
],
[
'code' => 'iu',
'native_name' => 'ᐃᓄᒃᑎᑐᑦ',
],
[
'code' => 'ja',
'native_name' => '日本語 (にほんご)',
],
[
'code' => 'jv',
'code' => 'jv',
'native_name' => 'ꦧꦱꦗꦮ, Basa Jawa',
],
['code' => 'ka', 'native_name' => 'ქართული'],
['code' => 'kg', 'native_name' => 'Kikongo'],
[
'code' => 'ki',
'code' => 'ka',
'native_name' => 'ქართული',
],
[
'code' => 'kg',
'native_name' => 'Kikongo',
],
[
'code' => 'ki',
'native_name' => 'Gĩkũyũ',
],
[
'code' => 'kj',
'code' => 'kj',
'native_name' => 'Kuanyama',
],
['code' => 'kk', 'native_name' => 'қазақ тілі'],
[
'code' => 'kl',
'native_name' => 'kalaallisut, kalaallit oqaasii',
'code' => 'kk',
'native_name' => 'қазақ тілі',
],
[
'code' => 'kl',
'native_name' => 'Kalaallisut, kalaallit oqaasii',
],
[
'code' => 'km',
'code' => 'km',
'native_name' => 'ខ្មែរ, ខេមរភាសា, ភាសាខ្មែរ',
],
['code' => 'kn', 'native_name' => 'ಕನ್ನಡ'],
['code' => 'ko', 'native_name' => '한국어'],
['code' => 'kr', 'native_name' => 'Kanuri'],
[
'code' => 'ks',
'code' => 'kn',
'native_name' => 'ಕನ್ನಡ',
],
[
'code' => 'ko',
'native_name' => '한국어',
],
[
'code' => 'kr',
'native_name' => 'Kanuri',
],
[
'code' => 'ks',
'native_name' => 'कश्मीरी, كشميري',
],
[
'code' => 'ku',
'code' => 'ku',
'native_name' => 'Kurdî, کوردی',
],
['code' => 'kv', 'native_name' => 'коми кыв'],
['code' => 'kw', 'native_name' => 'Kernewek'],
[
'code' => 'ky',
'code' => 'kv',
'native_name' => 'коми кыв',
],
[
'code' => 'kw',
'native_name' => 'Kernewek',
],
[
'code' => 'ky',
'native_name' => 'Кыргызча, Кыргыз тили',
],
[
'code' => 'la',
'native_name' => 'latine, lingua latina',
'code' => 'la',
'native_name' => 'Latine, lingua latina',
],
[
'code' => 'lb',
'code' => 'lb',
'native_name' => 'Lëtzebuergesch',
],
['code' => 'lg', 'native_name' => 'Luganda'],
[
'code' => 'li',
'code' => 'lg',
'native_name' => 'Luganda',
],
[
'code' => 'li',
'native_name' => 'Limburgs',
],
['code' => 'ln', 'native_name' => 'Lingála'],
['code' => 'lo', 'native_name' => 'ພາສາລາວ'],
[
'code' => 'lt',
'native_name' => 'lietuvių kalba',
'code' => 'ln',
'native_name' => 'Lingála',
],
[
'code' => 'lu',
'code' => 'lo',
'native_name' => 'ພາສາລາວ',
],
[
'code' => 'lt',
'native_name' => 'Lietuvių kalba',
],
[
'code' => 'lu',
'native_name' => 'Kiluba',
],
[
'code' => 'lv',
'native_name' => 'latviešu valoda',
'code' => 'lv',
'native_name' => 'Latviešu valoda',
],
[
'code' => 'mg',
'native_name' => 'fiteny malagasy',
'code' => 'mg',
'native_name' => 'Fiteny malagasy',
],
[
'code' => 'mh',
'code' => 'mh',
'native_name' => 'Kajin M̧ajeļ',
],
[
'code' => 'mi',
'native_name' => 'te reo Māori',
'code' => 'mi',
'native_name' => 'Te reo Māori',
],
[
'code' => 'mk',
'code' => 'mk',
'native_name' => 'македонски јазик',
],
['code' => 'ml', 'native_name' => 'മലയാളം'],
[
'code' => 'mn',
'code' => 'ml',
'native_name' => 'മലയാളം',
],
[
'code' => 'mn',
'native_name' => 'Монгол хэл',
],
['code' => 'mr', 'native_name' => 'मराठी'],
[
'code' => 'ms',
'code' => 'mr',
'native_name' => 'मराठी',
],
[
'code' => 'ms',
'native_name' => 'Bahasa Melayu, بهاس ملايو',
],
['code' => 'mt', 'native_name' => 'Malti'],
['code' => 'my', 'native_name' => 'ဗမာစာ'],
[
'code' => 'na',
'code' => 'mt',
'native_name' => 'Malti',
],
[
'code' => 'my',
'native_name' => 'ဗမာစာ',
],
[
'code' => 'na',
'native_name' => 'Dorerin Naoero',
],
[
'code' => 'nb',
'code' => 'nb',
'native_name' => 'Norsk Bokmål',
],
[
'code' => 'nd',
'code' => 'nd',
'native_name' => 'isiNdebele',
],
['code' => 'ne', 'native_name' => 'नेपाली'],
['code' => 'ng', 'native_name' => 'Owambo'],
[
'code' => 'nl',
'code' => 'ne',
'native_name' => 'नेपाली',
],
[
'code' => 'ng',
'native_name' => 'Owambo',
],
[
'code' => 'nl',
'native_name' => 'Nederlands, Vlaams',
],
[
'code' => 'nn',
'code' => 'nn',
'native_name' => 'Norsk Nynorsk',
],
['code' => 'no', 'native_name' => 'Norsk'],
[
'code' => 'nr',
'code' => 'no',
'native_name' => 'Norsk',
],
[
'code' => 'nr',
'native_name' => 'isiNdebele',
],
[
'code' => 'nv',
'code' => 'nv',
'native_name' => 'Diné bizaad',
],
[
'code' => 'ny',
'native_name' => 'chiCheŵa, chinyanja',
'code' => 'ny',
'native_name' => 'Chicheŵa, chinyanja',
],
[
'code' => 'oc',
'native_name' => 'Occitan, lenga d’òc',
],
[
'code' => 'oc',
'native_name' => 'occitan, lenga d’òc',
'code' => 'oj',
'native_name' => 'ᐊᓂᔑᓈᐯᒧᐎᓐ',
],
['code' => 'oj', 'native_name' => 'ᐊᓂᔑᓈᐯᒧᐎᓐ'],
[
'code' => 'om',
'code' => 'om',
'native_name' => 'Afaan Oromoo',
],
['code' => 'or', 'native_name' => 'ଓଡ଼ିଆ'],
[
'code' => 'os',
'code' => 'or',
'native_name' => 'ଓଡ଼ିଆ',
],
[
'code' => 'os',
'native_name' => 'ирон æвзаг',
],
[
'code' => 'pa',
'code' => 'pa',
'native_name' => 'ਪੰਜਾਬੀ, پنجابی',
],
['code' => 'pi', 'native_name' => 'पालि, पाळि'],
[
'code' => 'pl',
'code' => 'pi',
'native_name' => 'पालि, पाळि',
],
[
'code' => 'pl',
'native_name' => 'język polski, polszczyzna',
],
[
'code' => 'ps',
'code' => 'ps',
'native_name' => 'پښتو',
],
[
'code' => 'pt',
'code' => 'pt',
'native_name' => 'Português',
],
[
'code' => 'qu',
'code' => 'qu',
'native_name' => 'Runa Simi, Kichwa',
],
[
'code' => 'rm',
'code' => 'rm',
'native_name' => 'Rumantsch Grischun',
],
['code' => 'rn', 'native_name' => 'Ikirundi'],
[
'code' => 'ro',
'code' => 'rn',
'native_name' => 'Ikirundi',
],
[
'code' => 'ro',
'native_name' => 'Română',
],
['code' => 'ru', 'native_name' => 'русский'],
[
'code' => 'rw',
'code' => 'ru',
'native_name' => 'Pусский',
],
[
'code' => 'rw',
'native_name' => 'Ikinyarwanda',
],
[
'code' => 'sa',
'code' => 'sa',
'native_name' => 'संस्कृतम्',
],
['code' => 'sc', 'native_name' => 'sardu'],
[
'code' => 'sd',
'code' => 'sc',
'native_name' => 'Sardu',
],
[
'code' => 'sd',
'native_name' => 'सिन्धी, سنڌي، سندھی',
],
[
'code' => 'se',
'code' => 'se',
'native_name' => 'Davvisámegiella',
],
[
'code' => 'sg',
'native_name' => 'yângâ tî sängö',
'code' => 'sg',
'native_name' => 'Yângâ tî sängö',
],
[
'code' => 'si',
'code' => 'si',
'native_name' => 'සිංහල',
],
[
'code' => 'sk',
'code' => 'sk',
'native_name' => 'Slovenčina, Slovenský Jazyk',
],
[
'code' => 'sl',
'code' => 'sl',
'native_name' => 'Slovenski Jezik, Slovenščina',
],
[
'code' => 'sm',
'native_name' => 'gagana fa\'a Samoa',
'code' => 'sm',
'native_name' => "Gagana fa'a Samoa",
],
['code' => 'sn', 'native_name' => 'chiShona'],
[
'code' => 'so',
'code' => 'sn',
'native_name' => 'chiShona',
],
[
'code' => 'so',
'native_name' => 'Soomaaliga, af Soomaali',
],
['code' => 'sq', 'native_name' => 'Shqip'],
[
'code' => 'sr',
'code' => 'sq',
'native_name' => 'Shqip',
],
[
'code' => 'sr',
'native_name' => 'српски језик',
],
['code' => 'ss', 'native_name' => 'SiSwati'],
[
'code' => 'st',
'code' => 'ss',
'native_name' => 'SiSwati',
],
[
'code' => 'st',
'native_name' => 'Sesotho',
],
[
'code' => 'su',
'code' => 'su',
'native_name' => 'Basa Sunda',
],
['code' => 'sv', 'native_name' => 'Svenska'],
['code' => 'sw', 'native_name' => 'Kiswahili'],
['code' => 'ta', 'native_name' => 'தமிழ்'],
['code' => 'te', 'native_name' => 'తెలుగు'],
[
'code' => 'tg',
'code' => 'sv',
'native_name' => 'Svenska',
],
[
'code' => 'sw',
'native_name' => 'Kiswahili',
],
[
'code' => 'ta',
'native_name' => 'தமிழ்',
],
[
'code' => 'te',
'native_name' => 'తెలుగు',
],
[
'code' => 'tg',
'native_name' => 'тоҷикӣ, toçikī, تاجیکی',
],
['code' => 'th', 'native_name' => 'ไทย'],
['code' => 'ti', 'native_name' => 'ትግርኛ'],
[
'code' => 'tk',
'code' => 'th',
'native_name' => 'ไทย',
],
[
'code' => 'ti',
'native_name' => 'ትግርኛ',
],
[
'code' => 'tk',
'native_name' => 'Türkmen, Түркмен',
],
[
'code' => 'tl',
'code' => 'tl',
'native_name' => 'Wikang Tagalog',
],
['code' => 'tn', 'native_name' => 'Setswana'],
[
'code' => 'to',
'code' => 'tn',
'native_name' => 'Setswana',
],
[
'code' => 'to',
'native_name' => 'Faka Tonga',
],
['code' => 'tr', 'native_name' => 'Türkçe'],
['code' => 'ts', 'native_name' => 'Xitsonga'],
[
'code' => 'tt',
'code' => 'tr',
'native_name' => 'Türkçe',
],
[
'code' => 'ts',
'native_name' => 'Xitsonga',
],
[
'code' => 'tt',
'native_name' => 'татар теле, tatar tele',
],
['code' => 'tw', 'native_name' => 'Twi'],
[
'code' => 'ty',
'code' => 'tw',
'native_name' => 'Twi',
],
[
'code' => 'ty',
'native_name' => 'Reo Tahiti',
],
[
'code' => 'ug',
'code' => 'ug',
'native_name' => 'ئۇيغۇرچە, Uyghurche',
],
[
'code' => 'uk',
'code' => 'uk',
'native_name' => 'Українська',
],
['code' => 'ur', 'native_name' => 'اردو'],
[
'code' => 'uz',
'code' => 'ur',
'native_name' => 'اردو',
],
[
'code' => 'uz',
'native_name' => 'Oʻzbek, Ўзбек, أۇزبېك',
],
['code' => 've', 'native_name' => 'Tshivenḓa'],
[
'code' => 'vi',
'code' => 've',
'native_name' => 'Tshivenḓa',
],
[
'code' => 'vi',
'native_name' => 'Tiếng Việt',
],
['code' => 'vo', 'native_name' => 'Volapük'],
['code' => 'wa', 'native_name' => 'Walon'],
['code' => 'wo', 'native_name' => 'Wollof'],
['code' => 'xh', 'native_name' => 'isiXhosa'],
['code' => 'yi', 'native_name' => 'ייִדיש'],
['code' => 'yo', 'native_name' => 'Yorùbá'],
[
'code' => 'za',
'code' => 'vo',
'native_name' => 'Volapük',
],
[
'code' => 'wa',
'native_name' => 'Walon',
],
[
'code' => 'wo',
'native_name' => 'Wollof',
],
[
'code' => 'xh',
'native_name' => 'isiXhosa',
],
[
'code' => 'yi',
'native_name' => 'ייִדיש',
],
[
'code' => 'yo',
'native_name' => 'Yorùbá',
],
[
'code' => 'za',
'native_name' => 'Saɯ cueŋƅ, Saw cuengh',
],
[
'code' => 'zh',
'code' => 'zh',
'native_name' => '中文 (Zhōngwén), 汉语, 漢語',
],
['code' => 'zu', 'native_name' => 'isiZulu'],
[
'code' => 'zu',
'native_name' => 'isiZulu',
],
];
$this->db
->table('languages')
->ignore(true)
->insertBatch($data);
foreach ($data as $languageLine) {
$this->db
->table('languages')
->ignore(true)
->insert($languageLine);
}
}
}
<?php
/**
* Class PlatformsSeeder
* Inserts values in platforms table in database
*
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Seeds;
use CodeIgniter\Database\Seeder;
class PlatformSeeder extends Seeder
{
public function run()
{
$data = [
[
'slug' => 'amazon',
'type' => 'podcasting',
'label' => 'Amazon Music and Audible',
'home_url' => 'https://music.amazon.com/podcasts',
'submit_url' => 'http://amazon.com/podcasters',
],
[
'slug' => 'antennapod',
'type' => 'podcasting',
'label' => 'AntennaPod',
'home_url' => 'https://antennapod.org/',
'submit_url' => 'https://api.podcastindex.org/signup',
],
[
'slug' => 'apple',
'type' => 'podcasting',
'label' => 'Apple Podcasts',
'home_url' => 'https://www.apple.com/itunes/podcasts/',
'submit_url' =>
'https://podcastsconnect.apple.com/my-podcasts/new-feed',
],
[
'slug' => 'blubrry',
'type' => 'podcasting',
'label' => 'Blubrry',
'home_url' => 'https://www.blubrry.com/',
'submit_url' => 'https://www.blubrry.com/addpodcast.php',
],
[
'slug' => 'breaker',
'type' => 'podcasting',
'label' => 'Breaker',
'home_url' => 'https://www.breaker.audio/',
'submit_url' => 'https://podcasters.breaker.audio/',
],
[
'slug' => 'castbox',
'type' => 'podcasting',
'label' => 'Castbox',
'home_url' => 'https://castbox.fm/',
'submit_url' =>
'https://helpcenter.castbox.fm/portal/kb/articles/submit-my-podcast',
],
[
'slug' => 'castopod',
'type' => 'podcasting',
'label' => 'Castopod',
'home_url' => 'https://castopod.org/',
'submit_url' => 'https://castopod.org/instances',
],
[
'slug' => 'castro',
'type' => 'podcasting',
'label' => 'Castro',
'home_url' => 'http://castro.fm/',
'submit_url' =>
'https://castro.fm/support/link-to-your-podcast-in-castro',
],
[
'slug' => 'chartable',
'type' => 'podcasting',
'label' => 'Chartable',
'home_url' => 'https://chartable.com/',
'submit_url' => 'https://chartable.com/podcasts/submit',
],
[
'slug' => 'deezer',
'type' => 'podcasting',
'label' => 'Deezer',
'home_url' => 'https://www.deezer.com/',
'submit_url' => 'https://podcasters.deezer.com/submission',
],
[
'slug' => 'fyyd',
'type' => 'podcasting',
'label' => 'fyyd',
'home_url' => 'https://fyyd.de/',
'submit_url' => 'https://fyyd.de/add-feed',
],
[
'slug' => 'google',
'type' => 'podcasting',
'label' => 'Google Podcasts',
'home_url' => 'https://podcasts.google.com/about',
'submit_url' =>
'https://search.google.com/search-console/about',
],
[
'slug' => 'ivoox',
'type' => 'podcasting',
'label' => 'Ivoox',
'home_url' => 'https://www.ivoox.com/',
'submit_url' => 'http://www.ivoox.com/upload-podcast_u.html',
],
[
'slug' => 'listennotes',
'type' => 'podcasting',
'label' => 'ListenNotes',
'home_url' => 'https://www.listennotes.com/',
'submit_url' => 'https://www.listennotes.com/submit/',
],
[
'slug' => 'overcast',
'type' => 'podcasting',
'label' => 'Overcast',
'home_url' => 'https://overcast.fm/',
'submit_url' => 'https://overcast.fm/podcasterinfo',
],
[
'slug' => 'playerfm',
'type' => 'podcasting',
'label' => 'Player.Fm',
'home_url' => 'https://player.fm/',
'submit_url' => 'https://player.fm/importer/feed',
],
[
'slug' => 'pocketcasts',
'type' => 'podcasting',
'label' => 'Pocketcasts',
'home_url' => 'https://www.pocketcasts.com/',
'submit_url' => 'https://www.pocketcasts.com/submit/',
],
[
'slug' => 'podbean',
'type' => 'podcasting',
'label' => 'Podbean',
'home_url' => 'https://www.podbean.com/',
'submit_url' => 'https://www.podbean.com/site/submitPodcast',
],
[
'slug' => 'podcastaddict',
'type' => 'podcasting',
'label' => 'Podcast Addict',
'home_url' => 'https://podcastaddict.com/',
'submit_url' => 'https://podcastaddict.com/submit',
],
[
'slug' => 'podcastindex',
'type' => 'podcasting',
'label' => 'Podcast Index',
'home_url' => 'https://podcastindex.org/',
'submit_url' => 'https://api.podcastindex.org/signup',
],
[
'slug' => 'podchaser',
'type' => 'podcasting',
'label' => 'Podchaser',
'home_url' => 'https://www.podchaser.com/',
'submit_url' => 'https://www.podchaser.com/creators/edit',
],
[
'slug' => 'podcloud',
'type' => 'podcasting',
'label' => 'podCloud',
'home_url' => 'https://podcloud.fr/',
'submit_url' => 'https://podcloud.fr/studio/podcasts/new',
],
[
'slug' => 'podinstall',
'type' => 'podcasting',
'label' => 'Podinstall',
'home_url' => 'https://www.podinstall.com/',
'submit_url' => 'https://www.podinstall.com/claim.html',
],
[
'slug' => 'podlink',
'type' => 'podcasting',
'label' => 'pod.link',
'home_url' => 'https://pod.link/',
'submit_url' => 'https://pod.link',
],
[
'slug' => 'podtail',
'type' => 'podcasting',
'label' => 'Podtail',
'home_url' => 'https://podtail.com/',
'submit_url' => 'https://podtail.com/about/faq/',
],
[
'slug' => 'podfriend',
'type' => 'podcasting',
'label' => 'Podfriend',
'home_url' => 'https://www.podfriend.com/',
'submit_url' => 'https://api.podcastindex.org/signup',
],
[
'slug' => 'podverse',
'type' => 'podcasting',
'label' => 'Podverse',
'home_url' => 'https://podverse.fm/',
'submit_url' =>
'https://docs.google.com/forms/d/e/1FAIpQLSdewKP-YrE8zGjDPrkmoJEwCxPl_gizEkmzAlTYsiWAuAk1Ng/viewform',
],
[
'slug' => 'radiopublic',
'type' => 'podcasting',
'label' => 'RadioPublic',
'home_url' => 'https://radiopublic.com/',
'submit_url' => 'https://podcasters.radiopublic.com/signup',
],
[
'slug' => 'spotify',
'type' => 'podcasting',
'label' => 'Spotify',
'home_url' => 'https://www.spotify.com/',
'submit_url' => 'https://podcasters.spotify.com/submit',
],
[
'slug' => 'spreaker',
'type' => 'podcasting',
'label' => 'Spreaker',
'home_url' => 'https://www.spreaker.com/',
'submit_url' => 'https://www.spreaker.com/cms/shows/rss-import',
],
[
'slug' => 'stitcher',
'type' => 'podcasting',
'label' => 'Stitcher',
'home_url' => 'https://www.stitcher.com/',
'submit_url' => 'https://partners.stitcher.com/join',
],
[
'slug' => 'tunein',
'type' => 'podcasting',
'label' => 'TuneIn',
'home_url' => 'https://tunein.com/',
'submit_url' =>
'https://help.tunein.com/contact/add-podcast-S19TR3Sdf',
],
[
'slug' => 'paypal',
'type' => 'funding',
'label' => 'Paypal',
'home_url' => 'https://www.paypal.com/',
'submit_url' => 'https://www.paypal.com/paypalme/my/grab',
],
[
'slug' => 'gofundme',
'type' => 'funding',
'label' => 'GoFundMe',
'home_url' => 'https://www.gofundme.com/',
'submit_url' => 'https://www.gofundme.com/sign-up',
],
[
'slug' => 'helloasso',
'type' => 'funding',
'label' => 'helloasso',
'home_url' => 'https://www.helloasso.com/',
'submit_url' => 'https://auth.helloasso.com/inscription',
],
[
'slug' => 'indiegogo',
'type' => 'funding',
'label' => 'Indiegogo',
'home_url' => 'https://www.indiegogo.com/',
'submit_url' => 'https://www.indiegogo.com/start-a-campaign#/',
],
[
'slug' => 'kickstarter',
'type' => 'funding',
'label' => 'Kickstarter',
'home_url' => 'https://www.kickstarter.com/',
'submit_url' => 'https://www.kickstarter.com/learn',
],
[
'slug' => 'kisskissbankbank',
'type' => 'funding',
'label' => 'KissKissBankBank',
'home_url' => 'https://www.kisskissbankbank.com/',
'submit_url' =>
'https://www.kisskissbankbank.com/en/financer-mon-projet',
],
[
'slug' => 'liberapay',
'type' => 'funding',
'label' => 'Liberapay',
'home_url' => 'https://liberapay.com/',
'submit_url' => 'https://liberapay.com/sign-up',
],
[
'slug' => 'patreon',
'type' => 'funding',
'label' => 'Patreon',
'home_url' => 'https://www.patreon.com/',
'submit_url' => 'https://www.patreon.com/create',
],
[
'slug' => 'tipeee',
'type' => 'funding',
'label' => 'Tipeee',
'home_url' => 'https://tipeee.com/',
'submit_url' => 'https://tipeee.com/register/',
],
[
'slug' => 'ulule',
'type' => 'funding',
'label' => 'Ulule',
'home_url' => 'https://www.ulule.com/',
'submit_url' => 'https://www.ulule.com/projects/create/#/',
],
[
'slug' => 'discord',
'type' => 'social',
'label' => 'Discord',
'home_url' => 'https://discord.com/',
'submit_url' => 'https://discord.com/register',
],
[
'slug' => 'facebook',
'type' => 'social',
'label' => 'Facebook',
'home_url' => 'https://www.facebook.com/',
'submit_url' =>
'https://www.facebook.com/pages/creation/?ref_type=comet_home',
],
[
'slug' => 'funkwhale',
'type' => 'social',
'label' => 'Funkwhale',
'home_url' => 'https://funkwhale.audio/',
'submit_url' => 'https://network.funkwhale.audio/dashboards/',
],
[
'slug' => 'instagram',
'type' => 'social',
'label' => 'Instagram',
'home_url' => 'https://www.instagram.com/',
'submit_url' =>
'https://www.instagram.com/accounts/emailsignup/',
],
[
'slug' => 'linkedin',
'type' => 'social',
'label' => 'LinkedIn',
'home_url' => 'https://www.linkedin.com/',
'submit_url' => 'https://www.linkedin.com/company/setup/new/',
],
[
'slug' => 'mastodon',
'type' => 'social',
'label' => 'Mastodon',
'home_url' => 'https://joinmastodon.org/',
'submit_url' => 'https://joinmastodon.org/communities',
],
[
'slug' => 'mobilizon',
'type' => 'social',
'label' => 'Mobilizon',
'home_url' => 'https://joinmobilizon.org/',
'submit_url' => 'https://instances.joinmobilizon.org/instances',
],
[
'slug' => 'peertube',
'type' => 'social',
'label' => 'PeerTube',
'home_url' => 'https://joinpeertube.org/',
'submit_url' => 'https://joinpeertube.org/instances',
],
[
'slug' => 'pixelfed',
'type' => 'social',
'label' => 'Pixelfed',
'home_url' => 'https://pixelfed.org/',
'submit_url' => 'https://beta.joinpixelfed.org/',
],
[
'slug' => 'plume',
'type' => 'social',
'label' => 'Plume',
'home_url' => 'https://joinplu.me/',
'submit_url' => 'https://joinplu.me/#instances',
],
[
'slug' => 'slack',
'type' => 'social',
'label' => 'Slack',
'home_url' => 'https://slack.com/',
'submit_url' => 'https://slack.com/get-started#/create',
],
[
'slug' => 'twitch',
'type' => 'social',
'label' => 'Twitch',
'home_url' => 'https://www.twitch.tv/',
'submit_url' => 'https://www.twitch.tv/signup',
],
[
'slug' => 'twitter',
'type' => 'social',
'label' => 'Twitter',
'home_url' => 'https://twitter.com/',
'submit_url' => 'https://twitter.com/i/flow/signup',
],
[
'slug' => 'writefreely',
'type' => 'social',
'label' => 'WriteFreely',
'home_url' => 'https://writefreely.org/',
'submit_url' => 'https://writefreely.org/instances',
],
[
'slug' => 'youtube',
'type' => 'social',
'label' => 'Youtube',
'home_url' => 'https://www.youtube.com/',
'submit_url' => 'https://creatoracademy.youtube.com/page/home',
],
];
$this->db
->table('platforms')
->ignore(true)
->insertBatch($data);
}
}
<?php
/**
* Class TestSeeder
* Inserts a superadmin user in the database
*
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Seeds;
use CodeIgniter\Database\Seeder;
class TestSeeder extends Seeder
{
public function run()
{
/** Inserts an active user with the following credentials:
* username: admin
* password: AGUehL3P
*/
$this->db->table('users')->insert([
'id' => 1,
'username' => 'admin',
'email' => 'admin@example.com',
'password_hash' =>
'$2y$10$TXJEHX/djW8jtzgpDVf7dOOCGo5rv1uqtAYWdwwwkttQcDkAeB2.6',
'active' => 1,
]);
$this->db
->table('auth_groups_users')
->insert(['group_id' => 1, 'user_id' => 1]);
}
}
<?php
declare(strict_types=1);
/**
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use App\Models\PodcastModel;
use Modules\Fediverse\Entities\Actor as FediverseActor;
use Override;
use RuntimeException;
/**
* @property Podcast|null $podcast
* @property boolean $is_podcast
*/
class Actor extends FediverseActor
{
protected ?Podcast $podcast = null;
protected bool $is_podcast = false;
public function getIsPodcast(): bool
{
return $this->getPodcast() instanceof Podcast;
}
public function getPodcast(): ?Podcast
{
if ($this->id === null) {
throw new RuntimeException('Podcast id must be set before getting associated podcast.');
}
if (! $this->podcast instanceof Podcast) {
$this->podcast = (new PodcastModel())->getPodcastByActorId($this->id);
}
return $this->podcast;
}
#[Override]
public function getAvatarImageUrl(): string
{
if ($this->podcast instanceof Podcast) {
return $this->podcast->cover->thumbnail_url;
}
return parent::getAvatarImageUrl();
}
#[Override]
public function getAvatarImageMimetype(): string
{
if ($this->podcast instanceof Podcast) {
return $this->podcast->cover->thumbnail_mimetype;
}
return parent::getAvatarImageMimetype();
}
}
<?php
declare(strict_types=1);
/**
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
......@@ -9,29 +11,37 @@
namespace App\Entities;
use App\Models\CategoryModel;
use CodeIgniter\Entity;
use CodeIgniter\Entity\Entity;
/**
* @property int $id
* @property int $parent_id
* @property Category|null $parent
* @property string $code
* @property string $apple_category
* @property string $google_category
*/
class Category extends Entity
{
protected ?Category $parent = null;
/**
* @var \App\Entity\Category|null
* @var array<string, string>
*/
protected $parent;
protected $casts = [
'id' => 'integer',
'parent_id' => 'integer',
'code' => 'string',
'apple_category' => 'string',
'id' => 'integer',
'parent_id' => '?integer',
'code' => 'string',
'apple_category' => 'string',
'google_category' => 'string',
];
public function getParent()
public function getParent(): ?self
{
$parentId = $this->attributes['parent_id'];
if ($this->parent_id === null) {
return null;
}
return $parentId != 0
? (new CategoryModel())->findParent($parentId)
: null;
return (new CategoryModel())->getCategoryById($this->parent_id);
}
}
<?php
declare(strict_types=1);
/**
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities\Clip;
use App\Entities\Episode;
use App\Entities\Podcast;
use App\Models\EpisodeModel;
use App\Models\PodcastModel;
use CodeIgniter\Entity\Entity;
use CodeIgniter\Files\File;
use CodeIgniter\I18n\Time;
use CodeIgniter\Shield\Entities\User;
use Modules\Auth\Models\UserModel;
use Modules\Media\Entities\Audio;
use Modules\Media\Entities\Video;
use Modules\Media\Models\MediaModel;
/**
* @property int $id
* @property int $podcast_id
* @property Podcast $podcast
* @property int $episode_id
* @property Episode $episode
* @property string $title
* @property double $start_time
* @property double $end_time
* @property double $duration
* @property string $type
* @property int|null $media_id
* @property Video|Audio|null $media
* @property array<mixed>|null $metadata
* @property string $status
* @property string $logs
* @property User $user
* @property int $created_by
* @property int $updated_by
* @property Time|null $job_started_at
* @property Time|null $job_ended_at
*/
class BaseClip extends Entity
{
/**
* @var Video|Audio|null
*/
protected $media;
protected ?int $job_duration = null;
protected ?float $end_time = null;
/**
* @var array<int, string>
* @phpstan-var list<string>
*/
protected $dates = ['created_at', 'updated_at', 'job_started_at', 'job_ended_at'];
/**
* @var array<string, string>
*/
protected $casts = [
'id' => 'integer',
'podcast_id' => 'integer',
'episode_id' => 'integer',
'title' => 'string',
'start_time' => 'double',
'duration' => 'double',
'type' => 'string',
'media_id' => '?integer',
'metadata' => '?json-array',
'status' => 'string',
'logs' => 'string',
'created_by' => 'integer',
'updated_by' => 'integer',
];
/**
* @param array<string, mixed>|null $data
*/
public function __construct(?array $data = null)
{
parent::__construct($data);
}
public function getJobDuration(): ?int
{
if ($this->job_duration === null && $this->job_started_at && $this->job_ended_at) {
$this->job_duration = ($this->job_started_at->difference($this->job_ended_at))
->getSeconds();
}
return $this->job_duration;
}
public function getEndTime(): float
{
if ($this->end_time === null) {
$this->end_time = $this->start_time + $this->duration;
}
return $this->end_time;
}
public function getPodcast(): ?Podcast
{
return (new PodcastModel())->getPodcastById($this->podcast_id);
}
public function getEpisode(): ?Episode
{
return (new EpisodeModel())->getEpisodeById($this->episode_id);
}
public function getUser(): ?User
{
/** @var ?User */
return (new UserModel())->find($this->created_by);
}
public function setMedia(File $file, string $fileKey): static
{
if ($this->media_id !== null) {
$this->getMedia()
->setFile($file);
$this->getMedia()
->updated_by = $this->attributes['updated_by'];
(new MediaModel('audio'))->updateMedia($this->getMedia());
} else {
$media = new Audio([
'file_key' => $fileKey,
'language_code' => $this->getPodcast()
->language_code,
'uploaded_by' => $this->attributes['updated_by'],
'updated_by' => $this->attributes['updated_by'],
]);
$media->setFile($file);
$this->attributes['media_id'] = (new MediaModel())->saveMedia($media);
}
return $this;
}
public function getMedia(): Audio | Video | null
{
if ($this->media_id !== null && $this->media === null) {
$this->media = (new MediaModel($this->type))->getMediaById($this->media_id);
}
return $this->media;
}
}
<?php
declare(strict_types=1);
/**
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities\Clip;
class Soundbite extends BaseClip
{
protected string $type = 'audio';
}
<?php
declare(strict_types=1);
/**
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities\Clip;
use CodeIgniter\Files\File;
use Modules\Media\Entities\Video;
use Modules\Media\Models\MediaModel;
use Override;
/**
* @property array{name:string,preview:string} $theme
* @property string $format
*/
class VideoClip extends BaseClip
{
protected string $type = 'video';
/**
* @param array<string, mixed>|null $data
*/
public function __construct(?array $data = null)
{
parent::__construct($data);
if ($this->metadata !== null && $this->metadata !== []) {
$this->theme = $this->metadata['theme'];
$this->format = $this->metadata['format'];
}
}
/**
* @param array{name:string,preview:string} $theme
*/
public function setTheme(array $theme): self
{
// TODO: change?
$this->attributes['metadata'] = json_decode($this->attributes['metadata'] ?? '[]', true);
$this->attributes['theme'] = $theme;
$this->attributes['metadata']['theme'] = $theme;
$this->attributes['metadata'] = json_encode($this->attributes['metadata']);
return $this;
}
public function setFormat(string $format): self
{
$this->attributes['metadata'] = json_decode((string) $this->attributes['metadata'], true);
$this->attributes['format'] = $format;
$this->attributes['metadata']['format'] = $format;
$this->attributes['metadata'] = json_encode($this->attributes['metadata']);
return $this;
}
#[Override]
public function setMedia(File $file, string $fileKey): static
{
if ($this->attributes['media_id'] !== null) {
// media is already set, do nothing
return $this;
}
$video = new Video([
'file_key' => $fileKey,
'language_code' => $this->getPodcast()
->language_code,
'uploaded_by' => $this->attributes['created_by'],
'updated_by' => $this->attributes['created_by'],
]);
$video->setFile($file);
$this->attributes['media_id'] = (new MediaModel('video'))->saveMedia($video);
return $this;
}
}
<?php
declare(strict_types=1);
/**
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use App\Models\EpisodeModel;
use App\Models\PersonModel;
use App\Models\PodcastModel;
use App\Models\EpisodeModel;
use CodeIgniter\Entity;
use CodeIgniter\Entity\Entity;
use RuntimeException;
/**
* @property int $podcast_id
* @property Podcast|null $podcast
* @property int|null $episode_id
* @property Episode|null $episode
* @property string $full_name
* @property string $person_group
* @property string $group_label
* @property string $person_role
* @property string $role_label
* @property int $person_id
* @property Person|null $person
*/
class Credit extends Entity
{
/**
* @var \App\Entities\Person
*/
protected $person;
protected ?Person $person = null;
/**
* @var \App\Entities\Podcast
*/
protected $podcast;
protected ?Podcast $podcast = null;
/**
* @var \App\Entities\Episode|null
*/
protected $episode;
protected ?Episode $episode = null;
/**
* @var string
*/
protected $group_label;
protected string $group_label;
protected string $role_label;
/**
* @var string
* @var array<string, string>
*/
protected $role_label;
public function getPodcast()
protected $casts = [
'podcast_id' => 'integer',
'episode_id' => '?integer',
'person_id' => 'integer',
'full_name' => 'string',
'person_group' => 'string',
'person_role' => 'string',
];
public function getPerson(): ?Person
{
return (new PodcastModel())->getPodcastById(
$this->attributes['podcast_id'],
);
if ($this->person_id === null) {
throw new RuntimeException('Credit must have person_id before getting person.');
}
if (! $this->person instanceof Person) {
$this->person = (new PersonModel())->getPersonById($this->person_id);
}
return $this->person;
}
public function getEpisode()
public function getPodcast(): ?Podcast
{
if (empty($this->episode_id)) {
throw new \RuntimeException(
'Credit must have episode_id before getting episode.',
);
if ($this->podcast_id === null) {
throw new RuntimeException('Credit must have podcast_id before getting podcast.');
}
if (empty($this->episode)) {
$this->episode = (new EpisodeModel())->getPublishedEpisodeById(
$this->episode_id,
$this->podcast_id,
);
if (! $this->podcast instanceof Podcast) {
$this->podcast = (new PodcastModel())->getPodcastById($this->podcast_id);
}
return $this->episode;
return $this->podcast;
}
public function getPerson()
public function getEpisode(): ?Episode
{
if (empty($this->person_id)) {
throw new \RuntimeException(
'Credit must have person_id before getting person.',
);
if ($this->episode_id === null) {
throw new RuntimeException('Credit must have episode_id before getting episode.');
}
if (empty($this->person)) {
$this->person = (new PersonModel())->getPersonById(
$this->person_id,
);
if (! $this->episode instanceof Episode) {
$this->episode = (new EpisodeModel())->getPublishedEpisodeById($this->podcast_id, $this->episode_id);
}
return $this->person;
return $this->episode;
}
public function getGroupLabel()
public function getGroupLabel(): string
{
if (empty($this->person_group)) {
return null;
} else {
return lang("PersonsTaxonomy.persons.{$this->person_group}.label");
if ($this->person_group === null) {
return '';
}
/** @var string */
return lang("PersonsTaxonomy.persons.{$this->person_group}.label");
}
public function getRoleLabel()
public function getRoleLabel(): string
{
if (empty($this->person_group) || empty($this->person_role)) {
return null;
} else {
return lang(
"PersonsTaxonomy.persons.{$this->person_group}.roles.{$this->person_role}.label",
);
if ($this->person_group === '') {
return '';
}
if ($this->person_role === '') {
return '';
}
/** @var string */
return lang("PersonsTaxonomy.persons.{$this->person_group}.roles.{$this->person_role}.label");
}
}
<?php
declare(strict_types=1);
/**
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use App\Entities\Clip\Soundbite;
use App\Models\ClipModel;
use App\Models\EpisodeCommentModel;
use App\Models\EpisodeModel;
use App\Models\PersonModel;
use App\Models\PodcastModel;
use App\Models\SoundbiteModel;
use App\Models\EpisodePersonModel;
use App\Models\NoteModel;
use CodeIgniter\Entity;
use App\Models\PostModel;
use CodeIgniter\Entity\Entity;
use CodeIgniter\Files\File;
use CodeIgniter\HTTP\Files\UploadedFile;
use CodeIgniter\I18n\Time;
use League\CommonMark\CommonMarkConverter;
use Exception;
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
use League\CommonMark\MarkdownConverter;
use Modules\Media\Entities\Audio;
use Modules\Media\Entities\Chapters;
use Modules\Media\Entities\Image;
use Modules\Media\Entities\Transcript;
use Modules\Media\Models\MediaModel;
use Override;
use RuntimeException;
/**
* @property int $id
* @property int $podcast_id
* @property Podcast $podcast
* @property ?string $preview_id
* @property string $preview_link
* @property string $link
* @property string $guid
* @property string $slug
* @property string $title
* @property int $audio_id
* @property ?Audio $audio
* @property string $audio_url
* @property string $audio_web_url
* @property string $audio_opengraph_url
* @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 ?int $cover_id
* @property ?Image $cover
* @property int|null $transcript_id
* @property Transcript|null $transcript
* @property string|null $transcript_remote_url
* @property int|null $chapters_id
* @property Chapters|null $chapters
* @property string|null $chapters_remote_url
* @property string|null $parental_advisory
* @property int $number
* @property int $season_number
* @property string $type
* @property bool $is_blocked
* @property Location|null $location
* @property string|null $location_name
* @property string|null $location_geo
* @property string|null $location_osm
* @property bool $is_published_on_hubs
* @property int $downloads_count
* @property int $posts_count
* @property int $comments_count
* @property EpisodeComment[]|null $comments
* @property bool $is_premium
* @property int $created_by
* @property int $updated_by
* @property string $publication_status
* @property Time|null $published_at
* @property Time $created_at
* @property Time $updated_at
*
* @property Person[] $persons
* @property Soundbite[] $soundbites
* @property string $embed_url
*/
class Episode extends Entity
{
/**
* @var \App\Entities\Podcast
*/
protected $podcast;
public string $link = '';
/**
* @var string
*/
protected $link;
public string $audio_url = '';
/**
* @var \App\Libraries\Image
*/
protected $image;
public string $audio_web_url = '';
/**
* @var \CodeIgniter\Files\File
*/
protected $enclosure;
public string $audio_opengraph_url = '';
/**
* @var \CodeIgniter\Files\File
*/
protected $transcript;
protected Podcast $podcast;
/**
* @var \CodeIgniter\Files\File
*/
protected $chapters;
protected ?Audio $audio = null;
/**
* @var string
*/
protected $enclosure_media_path;
protected string $embed_url = '';
/**
* @var string
*/
protected $enclosure_url;
protected ?Image $cover = null;
/**
* @var string
*/
protected $enclosure_web_url;
protected ?string $description = null;
/**
* @var string
*/
protected $enclosure_opengraph_url;
protected ?Transcript $transcript = null;
/**
* @var string
*/
protected $transcript_url;
protected ?Chapters $chapters = null;
/**
* @var string
* @var Person[]|null
*/
protected $chapters_url;
protected ?array $persons = null;
/**
* @var \App\Entities\EpisodePerson[]
* @var Soundbite[]|null
*/
protected $persons;
protected ?array $soundbites = null;
/**
* @var \App\Entities\Soundbite[]
* @var Post[]|null
*/
protected $soundbites;
protected ?array $posts = null;
/**
* @var \App\Entities\Note[]
* @var EpisodeComment[]|null
*/
protected $notes;
protected ?array $comments = null;
/**
* Holds text only description, striped of any markdown or html special characters
*
* @var string
*/
protected $description;
protected ?Location $location = null;
/**
* The embeddable player URL
*
* @var string
*/
protected $embeddable_player;
protected ?string $publication_status = null;
/**
* @var string
* @var array<int, string>
* @phpstan-var list<string>
*/
protected $publication_status;
protected $dates = ['published_at', 'created_at', 'updated_at'];
/**
* Return custom rss as string
*
* @var string
* @var array<string, string>
*/
protected $custom_rss_string;
protected $dates = [
'published_at',
'created_at',
'updated_at',
'deleted_at',
];
protected $casts = [
'id' => 'integer',
'podcast_id' => 'integer',
'guid' => 'string',
'slug' => 'string',
'title' => 'string',
'enclosure_uri' => 'string',
'enclosure_duration' => 'integer',
'enclosure_mimetype' => 'string',
'enclosure_filesize' => 'integer',
'enclosure_headersize' => 'integer',
'description_markdown' => 'string',
'description_html' => 'string',
'image_uri' => '?string',
'image_mimetype' => '?string',
'transcript_uri' => '?string',
'chapters_uri' => '?string',
'parental_advisory' => '?string',
'number' => '?integer',
'season_number' => '?integer',
'type' => 'string',
'is_blocked' => 'boolean',
'location_name' => '?string',
'location_geo' => '?string',
'location_osmid' => '?string',
'custom_rss' => '?json-array',
'favourites_total' => 'integer',
'reblogs_total' => 'integer',
'notes_total' => 'integer',
'created_by' => 'integer',
'updated_by' => 'integer',
'id' => 'integer',
'podcast_id' => 'integer',
'preview_id' => '?string',
'guid' => 'string',
'slug' => 'string',
'title' => 'string',
'audio_id' => 'integer',
'description_markdown' => 'string',
'description_html' => 'string',
'cover_id' => '?integer',
'transcript_id' => '?integer',
'transcript_remote_url' => '?string',
'chapters_id' => '?integer',
'chapters_remote_url' => '?string',
'parental_advisory' => '?string',
'number' => '?integer',
'season_number' => '?integer',
'type' => 'string',
'is_blocked' => 'boolean',
'location_name' => '?string',
'location_geo' => '?string',
'location_osm' => '?string',
'is_published_on_hubs' => 'boolean',
'downloads_count' => 'integer',
'posts_count' => 'integer',
'comments_count' => 'integer',
'is_premium' => 'boolean',
'created_by' => 'integer',
'updated_by' => 'integer',
];
/**
* Saves an episode image
*
* @param \CodeIgniter\HTTP\Files\UploadedFile|\CodeIgniter\Files\File $image
*
* @param array<string, mixed> $data
*/
public function setImage($image)
#[Override]
public function injectRawData(array $data): static
{
if (
!empty($image) &&
(!($image instanceof \CodeIgniter\HTTP\Files\UploadedFile) ||
$image->isValid())
) {
helper('media');
// check whether the user has inputted an image and store
$this->attributes['image_mimetype'] = $image->getMimeType();
$this->attributes['image_uri'] = save_media(
$image,
'podcasts/' . $this->getPodcast()->name,
$this->attributes['slug'],
);
$this->image = new \App\Libraries\Image(
$this->attributes['image_uri'],
$this->attributes['image_mimetype'],
);
$this->image->saveSizes();
}
parent::injectRawData($data);
$this->link = url_to('episode', esc($this->getPodcast()->handle, 'url'), esc($this->attributes['slug'], 'url'));
$this->audio_url = url_to(
'episode-audio',
$this->getPodcast()
->handle,
$this->slug,
$this->getAudio()
->file_extension,
);
$this->audio_opengraph_url = $this->audio_url . '?_from=-+Open+Graph+-';
$this->audio_web_url = $this->audio_url . '?_from=-+Website+-';
return $this;
}
public function getImage(): \App\Libraries\Image
public function setCover(UploadedFile | File|null $file = null): self
{
if ($image_uri = $this->attributes['image_uri']) {
return new \App\Libraries\Image(
$image_uri,
$this->attributes['image_mimetype'],
);
if (! $file instanceof File || ($file instanceof UploadedFile && ! $file->isValid())) {
return $this;
}
return $this->getPodcast()->image;
}
/**
* Saves an enclosure
*
* @param \CodeIgniter\HTTP\Files\UploadedFile|\CodeIgniter\Files\File $enclosure
*
*/
public function setEnclosure($enclosure = null)
{
if (
!empty($enclosure) &&
(!($enclosure instanceof \CodeIgniter\HTTP\Files\UploadedFile) ||
$enclosure->isValid())
) {
helper(['media', 'id3']);
$enclosure_metadata = get_file_tags($enclosure);
$this->attributes['enclosure_uri'] = save_media(
$enclosure,
'podcasts/' . $this->getPodcast()->name,
$this->attributes['slug'],
);
$this->attributes['enclosure_duration'] = round(
$enclosure_metadata['playtime_seconds'],
);
$this->attributes['enclosure_mimetype'] =
$enclosure_metadata['mime_type'];
$this->attributes['enclosure_filesize'] =
$enclosure_metadata['filesize'];
$this->attributes['enclosure_headersize'] =
$enclosure_metadata['avdataoffset'];
return $this;
if (array_key_exists('cover_id', $this->attributes) && $this->attributes['cover_id'] !== null) {
$this->getCover()
->setFile($file);
$this->getCover()
->updated_by = $this->attributes['updated_by'];
(new MediaModel('image'))->updateMedia($this->getCover());
} else {
$cover = new Image([
'file_key' => 'podcasts/' . $this->getPodcast()->handle . '/' . $this->attributes['slug'] . '.' . $file->getExtension(),
'sizes' => config('Images')
->podcastCoverSizes,
'uploaded_by' => $this->attributes['updated_by'],
'updated_by' => $this->attributes['updated_by'],
]);
$cover->setFile($file);
$this->attributes['cover_id'] = (new MediaModel('image'))->saveMedia($cover);
}
return $this;
}
/**
* Saves an episode transcript
*
* @param \CodeIgniter\HTTP\Files\UploadedFile|\CodeIgniter\Files\File $transcript
*
*/
public function setTranscript($transcript)
public function getCover(): Image
{
if (
!empty($transcript) &&
(!($transcript instanceof \CodeIgniter\HTTP\Files\UploadedFile) ||
$transcript->isValid())
) {
helper('media');
if ($this->cover instanceof Image) {
return $this->cover;
}
$this->attributes['transcript_uri'] = save_media(
$transcript,
$this->getPodcast()->name,
$this->attributes['slug'] . '-transcript',
);
if ($this->cover_id === null) {
$this->cover = $this->getPodcast()
->getCover();
return $this->cover;
}
return $this;
$this->cover = (new MediaModel('image'))->getMediaById($this->cover_id);
return $this->cover;
}
/**
* Saves an episode chapters
*
* @param \CodeIgniter\HTTP\Files\UploadedFile|\CodeIgniter\Files\File $chapters
*
*/
public function setChapters($chapters)
public function setAudio(UploadedFile | File|null $file = null): self
{
if (
!empty($chapters) &&
(!($chapters instanceof \CodeIgniter\HTTP\Files\UploadedFile) ||
$chapters->isValid())
) {
helper('media');
if (! $file instanceof File || ($file instanceof UploadedFile && ! $file->isValid())) {
return $this;
}
$this->attributes['chapters_uri'] = save_media(
$chapters,
$this->getPodcast()->name,
$this->attributes['slug'] . '-chapters',
);
if ($this->audio_id !== 0) {
$this->getAudio()
->setFile($file);
$this->getAudio()
->updated_by = $this->attributes['updated_by'];
(new MediaModel('audio'))->updateMedia($this->getAudio());
} else {
$audio = new Audio([
'file_key' => 'podcasts/' . $this->getPodcast()->handle . '/' . $file->getRandomName(),
'language_code' => $this->getPodcast()
->language_code,
'uploaded_by' => $this->attributes['updated_by'],
'updated_by' => $this->attributes['updated_by'],
]);
$audio->setFile($file);
$this->attributes['audio_id'] = (new MediaModel())->saveMedia($audio);
}
return $this;
}
public function getEnclosure()
public function getAudio(): Audio
{
return new \CodeIgniter\Files\File($this->getEnclosureMediaPath());
}
if (! $this->audio instanceof Audio) {
$this->audio = (new MediaModel('audio'))->getMediaById($this->audio_id);
}
public function getTranscript()
{
return $this->attributes['transcript_uri']
? new \CodeIgniter\Files\File($this->getTranscriptMediaPath())
: null;
return $this->audio;
}
public function getChapters()
public function setTranscript(UploadedFile | File|null $file = null): self
{
return $this->attributes['chapters_uri']
? new \CodeIgniter\Files\File($this->getChaptersMediaPath())
: null;
}
if (! $file instanceof File || ($file instanceof UploadedFile && ! $file->isValid())) {
return $this;
}
public function getEnclosureMediaPath()
{
helper('media');
if ($this->getTranscript() instanceof Transcript) {
$this->getTranscript()
->setFile($file);
$this->getTranscript()
->updated_by = $this->attributes['updated_by'];
(new MediaModel('transcript'))->updateMedia($this->getTranscript());
} else {
$transcript = new Transcript([
'file_key' => 'podcasts/' . $this->getPodcast()->handle . '/' . $this->attributes['slug'] . '-transcript.' . $file->getExtension(),
'language_code' => $this->getPodcast()
->language_code,
'uploaded_by' => $this->attributes['updated_by'],
'updated_by' => $this->attributes['updated_by'],
]);
$transcript->setFile($file);
$this->attributes['transcript_id'] = (new MediaModel('transcript'))->saveMedia($transcript);
}
return media_path($this->attributes['enclosure_uri']);
return $this;
}
public function getTranscriptMediaPath()
public function getTranscript(): ?Transcript
{
helper('media');
if ($this->transcript_id !== null && ! $this->transcript instanceof Transcript) {
$this->transcript = (new MediaModel('transcript'))->getMediaById($this->transcript_id);
}
return $this->attributes['transcript_uri']
? media_path($this->attributes['transcript_uri'])
: null;
return $this->transcript;
}
public function getChaptersMediaPath()
public function setChapters(UploadedFile | File|null $file = null): self
{
helper('media');
if (! $file instanceof File || ($file instanceof UploadedFile && ! $file->isValid())) {
return $this;
}
return $this->attributes['chapters_uri']
? media_path($this->attributes['chapters_uri'])
: null;
}
if ($this->getChapters() instanceof Chapters) {
$this->getChapters()
->setFile($file);
$this->getChapters()
->updated_by = $this->attributes['updated_by'];
(new MediaModel('chapters'))->updateMedia($this->getChapters());
} else {
$chapters = new Chapters([
'file_key' => 'podcasts/' . $this->getPodcast()->handle . '/' . $this->attributes['slug'] . '-chapters' . '.' . $file->getExtension(),
'language_code' => $this->getPodcast()
->language_code,
'uploaded_by' => $this->attributes['updated_by'],
'updated_by' => $this->attributes['updated_by'],
]);
$chapters->setFile($file);
$this->attributes['chapters_id'] = (new MediaModel('chapters'))->saveMedia($chapters);
}
public function getEnclosureUrl()
{
helper('analytics');
return generate_episode_analytics_url(
$this->podcast_id,
$this->id,
$this->enclosure_uri,
$this->enclosure_duration,
$this->enclosure_filesize,
$this->enclosure_headersize,
$this->published_at,
);
return $this;
}
public function getEnclosureWebUrl()
public function getChapters(): ?Chapters
{
return $this->getEnclosureUrl() . '?_from=-+Website+-';
}
if ($this->chapters_id !== null && ! $this->chapters instanceof Chapters) {
$this->chapters = (new MediaModel('chapters'))->getMediaById($this->chapters_id);
}
public function getEnclosureOpengraphUrl()
{
return $this->getEnclosureUrl() . '?_from=-+Open+Graph+-';
return $this->chapters;
}
public function getTranscriptUrl()
/**
* Gets transcript url from transcript file uri if it exists or returns the transcript_remote_url which can be null.
*/
public function getTranscriptUrl(): ?string
{
return $this->attributes['transcript_uri']
? base_url($this->getTranscriptMediaPath())
: null;
if ($this->transcript instanceof Transcript) {
return $this->transcript->file_url;
}
return $this->transcript_remote_url;
}
public function getChaptersUrl()
/**
* Gets chapters file url from chapters file uri if it exists or returns the chapters_remote_url which can be null.
*/
public function getChaptersFileUrl(): ?string
{
return $this->attributes['chapters_uri']
? base_url($this->getChaptersMediaPath())
: null;
if ($this->chapters instanceof Chapters) {
return $this->chapters->file_url;
}
return $this->chapters_remote_url;
}
/**
* Returns the episode's persons
*
* @return \App\Entities\EpisodePerson[]
* @return Person[]
*/
public function getPersons()
public function getPersons(): array
{
if (empty($this->id)) {
throw new \RuntimeException(
'Episode must be created before getting persons.',
);
if ($this->id === null) {
throw new RuntimeException('Episode must be created before getting persons.');
}
if (empty($this->persons)) {
$this->persons = (new EpisodePersonModel())->getPersonsByEpisodeId(
$this->podcast_id,
$this->id,
);
if ($this->persons === null) {
$this->persons = (new PersonModel())->getEpisodePersons($this->podcast_id, $this->id);
}
return $this->persons;
}
/**
* Returns the episode’s soundbites
* Returns the episode’s clips
*
* @return \App\Entities\Episode[]
* @return Soundbite[]
*/
public function getSoundbites()
public function getSoundbites(): array
{
if (empty($this->id)) {
throw new \RuntimeException(
'Episode must be created before getting soundbites.',
);
if ($this->id === null) {
throw new RuntimeException('Episode must be created before getting soundbites.');
}
if (empty($this->soundbites)) {
$this->soundbites = (new SoundbiteModel())->getEpisodeSoundbites(
$this->getPodcast()->id,
$this->id,
);
if ($this->soundbites === null) {
$this->soundbites = (new ClipModel())->getEpisodeSoundbites($this->getPodcast()->id, $this->id);
}
return $this->soundbites;
}
public function getNotes()
/**
* @return Post[]
*/
public function getPosts(): array
{
if (empty($this->id)) {
throw new \RuntimeException(
'Episode must be created before getting soundbites.',
);
if ($this->id === null) {
throw new RuntimeException('Episode must be created before getting posts.');
}
if (empty($this->notes)) {
$this->notes = (new NoteModel())->getEpisodeNotes($this->id);
if ($this->posts === null) {
$this->posts = (new PostModel())->getEpisodePosts($this->id);
}
return $this->notes;
return $this->posts;
}
public function getLink()
/**
* @return EpisodeComment[]
*/
public function getComments(): array
{
return base_url(
route_to(
'episode',
$this->getPodcast()->name,
$this->attributes['slug'],
),
);
if ($this->id === null) {
throw new RuntimeException('Episode must be created before getting comments.');
}
if ($this->comments === null) {
$this->comments = (new EpisodeCommentModel())->getEpisodeComments($this->id);
}
return $this->comments;
}
public function getEmbeddablePlayer($theme = null)
public function getEmbedUrl(?string $theme = null): string
{
return base_url(
$theme
? route_to(
'embeddable-player-theme',
$this->getPodcast()->name,
$this->attributes['slug'],
$theme,
)
: route_to(
'embeddable-player',
$this->getPodcast()->name,
$this->attributes['slug'],
),
);
return $theme
? url_to('embed-theme', esc($this->getPodcast()->handle), esc($this->attributes['slug']), $theme)
: url_to('embed', esc($this->getPodcast()->handle), esc($this->attributes['slug']));
}
public function setGuid(string $guid)
public function setGuid(?string $guid = null): static
{
return $this->attributes['guid'] = empty($guid)
? $this->getLink()
: $guid;
$this->attributes['guid'] = $guid ?? $this->link;
return $this;
}
public function getPodcast()
public function getPodcast(): ?Podcast
{
return (new PodcastModel())->getPodcastById(
$this->attributes['podcast_id'],
);
return (new PodcastModel())->getPodcastById($this->podcast_id);
}
public function setDescriptionMarkdown(string $descriptionMarkdown)
public function setDescriptionMarkdown(string $descriptionMarkdown): static
{
$converter = new CommonMarkConverter([
'html_input' => 'strip',
$config = [
'html_input' => 'escape',
'allow_unsafe_links' => false,
]);
];
$environment = new Environment($config);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new SmartPunctExtension());
$environment->addExtension(new DisallowedRawHtmlExtension());
$converter = new MarkdownConverter($environment);
$this->attributes['description_markdown'] = $descriptionMarkdown;
$this->attributes['description_html'] = $converter->convertToHtml(
$descriptionMarkdown,
);
$this->attributes['description_html'] = $converter->convert($descriptionMarkdown);
return $this;
}
public function getDescriptionHtml($serviceSlug = null)
public function getDescription(): string
{
return (empty($this->getPodcast()->partner_id) ||
empty($this->getPodcast()->partner_link_url) ||
empty($this->getPodcast()->partner_image_url)
? ''
: "<div><a href=\"{$this->getPartnerLink(
$serviceSlug,
)}\" rel=\"sponsored noopener noreferrer\" target=\"_blank\"><img src=\"{$this->getPartnerImage(
$serviceSlug,
)}\" alt=\"Partner image\" /></a></div>") .
$this->attributes['description_html'] .
(empty($this->getPodcast()->episode_description_footer_html)
? ''
: "<footer>{$this->getPodcast()->episode_description_footer_html}</footer>");
}
public function getDescription()
{
if ($this->description) {
return $this->description;
if ($this->description === null) {
$this->description = trim(
(string) preg_replace('~\s+~', ' ', strip_tags((string) $this->attributes['description_html'])),
);
}
return trim(
preg_replace(
'/\s+/',
' ',
strip_tags($this->attributes['description_html']),
),
);
return $this->description;
}
public function getPublicationStatus()
public function getPublicationStatus(): string
{
if ($this->publication_status) {
return $this->publication_status;
}
if (!$this->published_at) {
return 'not_published';
}
helper('date');
if ($this->published_at->isBefore(Time::now())) {
return 'published';
if ($this->publication_status === null) {
if (! $this->published_at instanceof Time) {
$this->publication_status = 'not_published';
} elseif ($this->getPodcast()->publication_status !== 'published') {
$this->publication_status = 'with_podcast';
} elseif ($this->published_at->isBefore(Time::now())) {
$this->publication_status = 'published';
} else {
$this->publication_status = 'scheduled';
}
}
return 'scheduled';
return $this->publication_status;
}
/**
* Saves the location name and fetches OpenStreetMap info
*
* @param string $locationName
*
*/
public function setLocation($locationName = null)
public function setLocation(?Location $location = null): static
{
helper('location');
if (! $location instanceof Location) {
$this->attributes['location_name'] = null;
$this->attributes['location_geo'] = null;
$this->attributes['location_osm'] = null;
return $this;
}
if (
$locationName &&
(empty($this->attributes['location_name']) ||
$this->attributes['location_name'] != $locationName)
! isset($this->attributes['location_name']) ||
$this->attributes['location_name'] !== $location->name
) {
$this->attributes['location_name'] = $locationName;
if ($location = fetch_osm_location($locationName)) {
$this->attributes['location_geo'] = $location['geo'];
$this->attributes['location_osmid'] = $location['osmid'];
}
} elseif (empty($locationName)) {
$this->attributes['location_name'] = null;
$this->attributes['location_geo'] = null;
$this->attributes['location_osmid'] = null;
$location->fetchOsmLocation();
$this->attributes['location_name'] = $location->name;
$this->attributes['location_geo'] = $location->geo;
$this->attributes['location_osm'] = $location->osm;
}
return $this;
}
/**
* Get custom rss tag as XML String
*
* @return string
*
*/
function getCustomRssString()
public function getLocation(): ?Location
{
helper('rss');
if (empty($this->attributes['custom_rss'])) {
return '';
} else {
$xmlNode = (new \App\Libraries\SimpleRSSElement(
'<?xml version="1.0" encoding="utf-8"?><rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:podcast="https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"/>',
))
->addChild('channel')
->addChild('item');
array_to_rss(
[
'elements' => $this->custom_rss,
],
$xmlNode,
);
return str_replace(['<item>', '</item>'], '', $xmlNode->asXML());
if ($this->location_name === null) {
return null;
}
}
/**
* Saves custom rss tag into json
*
* @param string $customRssString
*
*/
function setCustomRssString($customRssString)
{
helper('rss');
$customRssArray = rss_to_array(
simplexml_load_string(
'<?xml version="1.0" encoding="utf-8"?><rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:podcast="https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"><channel><item>' .
$customRssString .
'</item></channel></rss>',
),
)['elements'][0]['elements'][0];
if (array_key_exists('elements', $customRssArray)) {
$this->attributes['custom_rss'] = json_encode(
$customRssArray['elements'],
);
} else {
$this->attributes['custom_rss'] = null;
if (! $this->location instanceof Location) {
$this->location = new Location($this->location_name, $this->location_geo, $this->location_osm);
}
return $this->location;
}
function getPartnerLink($serviceSlug = null)
public function getPreviewLink(): string
{
return rtrim($this->getPodcast()->partner_link_url, '/') .
'?pid=' .
$this->getPodcast()->partner_id .
'&guid=' .
urlencode($this->attributes['guid']) .
(empty($serviceSlug) ? '' : '&_from=' . $serviceSlug);
if ($this->preview_id === null) {
// generate preview id
if (! $previewUUID = (new EpisodeModel())->setEpisodePreviewId($this->id)) {
throw new Exception('Could not set episode preview id');
}
$this->preview_id = $previewUUID;
}
return url_to('episode-preview', (string) $this->preview_id);
}
function getPartnerImage($serviceSlug = null)
/**
* Returns the episode's clip count
*/
public function getClipCount(): int|string
{
return rtrim($this->getPodcast()->partner_image_url, '/') .
'?pid=' .
$this->getPodcast()->partner_id .
'&guid=' .
urlencode($this->attributes['guid']) .
(empty($serviceSlug) ? '' : '&_from=' . $serviceSlug);
if ($this->id === null) {
throw new RuntimeException('Episode must be created before getting number of video clips.');
}
return (new ClipModel())->getClipCount($this->podcast_id, $this->id);
}
}
<?php
declare(strict_types=1);
/**
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use App\Models\ActorModel;
use App\Models\EpisodeCommentModel;
use App\Models\EpisodeModel;
use CodeIgniter\I18n\Time;
use Michalsn\Uuid\UuidEntity;
use RuntimeException;
/**
* @property string $id
* @property string $uri
* @property int $episode_id
* @property Episode|null $episode
* @property int $actor_id
* @property Actor|null $actor
* @property string $in_reply_to_id
* @property EpisodeComment|null $reply_to_comment
* @property string $message
* @property string $message_html
* @property int $likes_count
* @property int $replies_count
* @property Time $created_at
* @property int $created_by
*
* @property EpisodeComment[] $replies
*/
class EpisodeComment extends UuidEntity
{
protected ?Episode $episode = null;
protected ?Actor $actor = null;
protected ?EpisodeComment $reply_to_comment = null;
/**
* @var EpisodeComment[]|null
*/
protected ?array $replies = null;
protected bool $has_replies = false;
/**
* @var array<int, string>
* @phpstan-var list<string>
*/
protected $dates = ['created_at'];
/**
* @var array<string, string>
*/
protected $casts = [
'id' => 'string',
'uri' => 'string',
'episode_id' => 'integer',
'actor_id' => 'integer',
'in_reply_to_id' => '?string',
'message' => 'string',
'message_html' => 'string',
'likes_count' => 'integer',
'replies_count' => 'integer',
'created_by' => 'integer',
'is_from_post' => 'boolean',
];
public function getEpisode(): ?Episode
{
if ($this->episode_id === null) {
throw new RuntimeException('Comment must have an episode_id before getting episode.');
}
if (! $this->episode instanceof Episode) {
$this->episode = (new EpisodeModel())->getEpisodeById($this->episode_id);
}
return $this->episode;
}
/**
* Returns the comment's actor
*/
public function getActor(): ?Actor
{
if ($this->actor_id === null) {
throw new RuntimeException('Comment must have an actor_id before getting actor.');
}
if (! $this->actor instanceof Actor) {
$this->actor = model(ActorModel::class, false)
->getActorById($this->actor_id);
}
return $this->actor;
}
/**
* @return EpisodeComment[]
*/
public function getReplies(): array
{
if ($this->id === null) {
throw new RuntimeException('Comment must be created before getting replies.');
}
if ($this->replies === null) {
$this->replies = (new EpisodeCommentModel())->getCommentReplies($this->id);
}
return $this->replies;
}
public function getHasReplies(): bool
{
return $this->getReplies() !== [];
}
public function getReplyToComment(): ?self
{
if ($this->in_reply_to_id === null) {
throw new RuntimeException('Comment is not a reply.');
}
if (! $this->reply_to_comment instanceof self) {
$this->reply_to_comment = model(EpisodeCommentModel::class, false)
->getCommentById($this->in_reply_to_id);
}
return $this->reply_to_comment;
}
public function setMessage(string $message): static
{
helper('fediverse');
$messageWithoutTags = strip_tags($message);
$this->attributes['message'] = $messageWithoutTags;
$this->attributes['message_html'] = str_replace("\n", '<br />', linkify($messageWithoutTags));
return $this;
}
}
<?php
/**
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use CodeIgniter\Entity;
use App\Models\PersonModel;
class EpisodePerson extends Entity
{
/**
* @var \App\Entities\Person
*/
protected $person;
protected $casts = [
'id' => 'integer',
'podcast_id' => 'integer',
'episode_id' => 'integer',
'person_id' => 'integer',
'person_group' => '?string',
'person_role' => '?string',
];
public function getPerson()
{
return (new PersonModel())->getPersonById(
$this->attributes['person_id']
);
}
}
<?php
declare(strict_types=1);
/**
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use CodeIgniter\Entity;
use CodeIgniter\Entity\Entity;
/**
* @property string $code
* @property string $native_name
*/
class Language extends Entity
{
/**
* @var array<string, string>
*/
protected $casts = [
'code' => 'string',
'code' => 'string',
'native_name' => 'string',
];
}
<?php
declare(strict_types=1);
/**
* @copyright 2021 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use Michalsn\Uuid\UuidEntity;
/**
* @property int $actor_id
* @property string $comment_id
*/
class Like extends UuidEntity
{
/**
* @var string[]
*/
protected $uuids = ['comment_id'];
/**
* @var array<string, string>
*/
protected $casts = [
'actor_id' => 'integer',
'comment_id' => 'string',
];
}
<?php
declare(strict_types=1);
/**
* @copyright 2021 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use CodeIgniter\Entity\Entity;
/**
* @property string $url
* @property string $name
* @property string|null $geo
* @property string|null $osm
* @property double|null $latitude
* @property double|null $longitude
*/
class Location extends Entity
{
private const string OSM_URL = 'https://www.openstreetmap.org/';
private const string NOMINATIM_URL = 'https://nominatim.openstreetmap.org/';
public function __construct(
protected string $name,
protected ?string $geo = null,
protected ?string $osm = null,
) {
$latitude = null;
$longitude = null;
if ($geo !== null) {
$geoArray = explode(',', substr($geo, 4));
if (count($geoArray) === 2) {
$latitude = (float) $geoArray[0];
$longitude = (float) $geoArray[1];
}
}
parent::__construct([
'name' => $name,
'geo' => $geo,
'osm' => $osm,
'latitude' => $latitude,
'longitude' => $longitude,
]);
}
public function getUrl(): string
{
if ($this->osm !== null) {
return self::OSM_URL .
[
'N' => 'node',
'W' => 'way',
'R' => 'relation',
][substr($this->osm, 0, 1)] .
'/' .
substr($this->osm, 1);
}
if ($this->geo !== null) {
return self::OSM_URL .
'#map=17/' .
str_replace(',', '/', substr($this->geo, 4));
}
return self::OSM_URL . 'search?query=' . urlencode($this->name);
}
/**
* Fetches places from Nominatim OpenStreetMap
*/
public function fetchOsmLocation(): static
{
$client = service('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((string) $response->getBody(), false, 512, JSON_THROW_ON_ERROR);
if ($places === []) {
return $this;
}
if (property_exists($places[0], 'lat') && $places[0]->lat !== null && (property_exists(
$places[0],
'lon',
) && $places[0]->lon !== null)) {
$this->attributes['geo'] = "geo:{$places[0]->lat},{$places[0]->lon}";
}
if (property_exists($places[0], 'osm_type') && $places[0]->osm_type !== null && (property_exists(
$places[0],
'osm_id',
) && $places[0]->osm_id !== null)) {
$this->attributes['osm'] = strtoupper(substr((string) $places[0]->osm_type, 0, 1)) . $places[0]->osm_id;
}
return $this;
}
}
<?php
/**
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use App\Models\EpisodeModel;
class Note extends \ActivityPub\Entities\Note
{
/**
* @var \App\Entities\Episode|null
*/
protected $episode;
protected $casts = [
'id' => 'string',
'uri' => 'string',
'actor_id' => 'integer',
'in_reply_to_id' => '?string',
'reblog_of_id' => '?string',
'episode_id' => '?integer',
'message' => 'string',
'message_html' => 'string',
'favourites_count' => 'integer',
'reblogs_count' => 'integer',
'replies_count' => 'integer',
'created_by' => 'integer',
];
/**
* Returns the note's attached episode
*
* @return \App\Entities\Episode
*/
public function getEpisode()
{
if (empty($this->episode_id)) {
throw new \RuntimeException(
'Note must have an episode_id before getting episode.',
);
}
if (empty($this->episode)) {
$this->episode = (new EpisodeModel())->getEpisodeById(
$this->episode_id,
);
}
return $this->episode;
}
}
<?php
declare(strict_types=1);
/**
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use CodeIgniter\Entity;
use League\CommonMark\CommonMarkConverter;
use CodeIgniter\Entity\Entity;
use CodeIgniter\I18n\Time;
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
use League\CommonMark\MarkdownConverter;
/**
* @property int $id
* @property string $title
* @property string $link
* @property string $slug
* @property string $content_markdown
* @property string $content_html
* @property Time $created_at
* @property Time $updated_at
* @property Time|null $delete_at
*/
class Page extends Entity
{
/**
* @var string
*/
protected $link;
protected string $link;
protected string $content_html;
/**
* @var string
* @var array<string, string>
*/
protected $content_html;
protected $casts = [
'id' => 'integer',
'title' => 'string',
'slug' => 'string',
'content' => 'string',
'id' => 'integer',
'title' => 'string',
'slug' => 'string',
'content_markdown' => 'string',
'content_html' => 'string',
];
public function getLink()
public function getLink(): string
{
return base_url($this->attributes['slug']);
return url_to('page', $this->attributes['slug']);
}
public function getContentHtml()
public function setContentMarkdown(string $contentMarkdown): static
{
$converter = new CommonMarkConverter([
'html_input' => 'strip',
$config = [
'allow_unsafe_links' => false,
]);
];
$environment = new Environment($config);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new SmartPunctExtension());
$environment->addExtension(new DisallowedRawHtmlExtension());
$converter = new MarkdownConverter($environment);
$this->attributes['content_markdown'] = $contentMarkdown;
$this->attributes['content_html'] = $converter->convert($contentMarkdown);
return $converter->convertToHtml($this->attributes['content']);
return $this;
}
}
<?php
declare(strict_types=1);
/**
* @copyright 2021 Podlibre
* @copyright 2021 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use CodeIgniter\Entity;
use App\Models\PersonModel;
use CodeIgniter\Entity\Entity;
use CodeIgniter\Files\File;
use CodeIgniter\HTTP\Files\UploadedFile;
use Modules\Media\Entities\Image;
use Modules\Media\Models\MediaModel;
use RuntimeException;
/**
* @property int $id
* @property string $full_name
* @property string $unique_name
* @property string|null $information_url
* @property int $avatar_id
* @property ?Image $avatar
* @property int $created_by
* @property int $updated_by
* @property object[]|null $roles
*/
class Person extends Entity
{
protected ?Image $avatar = null;
/**
* @var \App\Libraries\Image
* @var object[]|null
*/
protected $image;
protected ?array $roles = null;
/**
* @var array<string, string>
*/
protected $casts = [
'id' => 'integer',
'full_name' => 'string',
'unique_name' => 'string',
'id' => 'integer',
'full_name' => 'string',
'unique_name' => 'string',
'information_url' => '?string',
'image_uri' => 'string',
'image_mimetype' => 'string',
'created_by' => 'integer',
'updated_by' => 'integer',
'avatar_id' => '?int',
'podcast_id' => '?integer',
'episode_id' => '?integer',
'created_by' => 'integer',
'updated_by' => 'integer',
];
/**
* Saves a picture in `public/media/persons/`
*
* @param \CodeIgniter\HTTP\Files\UploadedFile|\CodeIgniter\Files\File $image
*
* Saves the person avatar in `public/media/persons/`
*/
public function setImage($image = null)
public function setAvatar(UploadedFile | File|null $file = null): static
{
if ($image) {
helper('media');
$this->attributes['image_mimetype'] = $image->getMimeType();
$this->attributes['image_uri'] = save_media(
$image,
'persons',
$this->attributes['unique_name'],
);
$this->image = new \App\Libraries\Image(
$this->attributes['image_uri'],
$this->attributes['image_mimetype'],
);
$this->image->saveSizes();
if (! $file instanceof File || ($file instanceof UploadedFile && ! $file->isValid())) {
return $this;
}
if (array_key_exists('avatar_id', $this->attributes) && $this->attributes['avatar_id'] !== null) {
$this->getAvatar()
->setFile($file);
$this->getAvatar()
->updated_by = $this->attributes['updated_by'];
(new MediaModel('image'))->updateMedia($this->getAvatar());
} else {
$avatar = new Image([
'file_key' => 'persons/' . $this->attributes['unique_name'] . '.' . $file->getExtension(),
'sizes' => config('Images')
->personAvatarSizes,
'uploaded_by' => $this->attributes['updated_by'],
'updated_by' => $this->attributes['updated_by'],
]);
$avatar->setFile($file);
$this->attributes['avatar_id'] = (new MediaModel('image'))->saveMedia($avatar);
}
return $this;
}
public function getImage()
public function getAvatar(): ?Image
{
return new \App\Libraries\Image(
$this->attributes['image_uri'],
$this->attributes['image_mimetype'],
);
if ($this->avatar_id === null) {
return null;
}
if (! $this->avatar instanceof Image) {
$this->avatar = (new MediaModel('image'))->getMediaById($this->avatar_id);
}
return $this->avatar;
}
/**
* @return object[]
*/
public function getRoles(): array
{
if ($this->attributes['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,
(int) $this->attributes['podcast_id'],
array_key_exists('episode_id', $this->attributes) ? (int) $this->attributes['episode_id'] : null,
);
}
return $this->roles;
}
}