Пример #1
0
    function page()
    {
        ?>
		<div class="wrap">
			<div id="icon-options-general" class="icon32"></div>
			<h2><?php 
        echo __('Podcast Settings');
        ?>
</h2>

			<form method="post" action="options.php">
				<?php 
        settings_fields(Podcast::$pagehook);
        ?>

				<?php 
        $podcast = \Podlove\Model\Podcast::get_instance();
        $form_attributes = array('context' => 'podlove_podcast', 'form' => false);
        \Podlove\Form\build_for($podcast, $form_attributes, function ($form) {
            $wrapper = new \Podlove\Form\Input\TableWrapper($form);
            $podcast = $form->object;
            $wrapper->string('title', array('label' => __('Title', 'podlove'), 'description' => __('', 'podlove'), 'html' => array('class' => 'regular-text required')));
            $wrapper->string('subtitle', array('label' => __('Subtitle', 'podlove'), 'description' => __('The subtitle is used by iTunes.', 'podlove'), 'html' => array('class' => 'regular-text')));
            $wrapper->text('summary', array('label' => __('Summary', 'podlove'), 'description' => __('A couple of sentences describing the podcast.', 'podlove'), 'html' => array('rows' => 5, 'cols' => 40)));
            $wrapper->string('slug', array('label' => __('Mnemonic', 'podlove'), 'description' => __('The abbreviation for your podcast. Commonly the initials of the title.', 'podlove'), 'html' => array('class' => 'regular-text required')));
            $wrapper->image('cover_image', array('label' => __('Cover Art URL', 'podlove'), 'description' => __('JPEG or PNG. At least 1400 x 1400 pixels.', 'podlove'), 'html' => array('class' => 'regular-text'), 'image_width' => 300, 'image_height' => 300));
            $wrapper->string('author_name', array('label' => __('Author Name', 'podlove'), 'description' => __('Publicly displayed in Podcast directories.', 'podlove'), 'html' => array('class' => 'regular-text')));
            $wrapper->string('owner_name', array('label' => __('Owner Name', 'podlove'), 'description' => __('Used by iTunes and other Podcast directories to contact you.', 'podlove'), 'html' => array('class' => 'regular-text')));
            $wrapper->string('owner_email', array('label' => __('Owner Email', 'podlove'), 'description' => __('Used by iTunes and other Podcast directories to contact you.', 'podlove'), 'html' => array('class' => 'regular-text')));
            $wrapper->string('keywords', array('label' => __('Keywords', 'podlove'), 'description' => __('List of keywords. Separate with commas.', 'podlove'), 'html' => array('class' => 'regular-text')));
            $wrapper->select('category_1', array('label' => __('iTunes Categories', 'podlove'), 'description' => '', 'type' => 'select', 'options' => \Podlove\Itunes\categories()));
            $wrapper->select('category_2', array('label' => '', 'description' => '', 'type' => 'select', 'options' => \Podlove\Itunes\categories()));
            $wrapper->select('category_3', array('label' => '', 'description' => '<br>' . __('For placement within the older, text-based browse system, podcast feeds may list up to 3 category/subcategory pairs. (For example, "Music" counts as 1, as does "Business > Careers.") For placement within the newer browse system based on Category links, however, and for placement within the Top Podcasts and Top Episodes lists that appear in the right column of most podcast pages, only the first category listed in the feed is used.') . ' (<a href="http://www.apple.com/itunes/podcasts/specs.html#category" target="_blank">http://www.apple.com/itunes/podcasts/specs.html#category</a>)', 'options' => \Podlove\Itunes\categories()));
            $wrapper->select('language', array('label' => __('Language', 'podlove'), 'description' => __('', 'podlove'), 'default' => get_bloginfo('language'), 'options' => \Podlove\Locale\locales()));
            $wrapper->select('explicit', array('label' => __('Explicit Content?', 'podlove'), 'description' => __('', 'podlove'), 'type' => 'checkbox', 'options' => array(0 => 'no', 1 => 'yes', 2 => 'clean')));
            $wrapper->string('media_file_base_uri', array('label' => __('Media File Base URL', 'podlove'), 'description' => __('Example: http://cdn.example.com/pod/', 'podlove'), 'html' => array('class' => 'regular-text required')));
            $artwork_options = array('0' => __('None', 'podlove'), 'manual' => __('Manual Entry', 'podlove'));
            $episode_assets = Model\EpisodeAsset::all();
            foreach ($episode_assets as $episode_asset) {
                $file_type = $episode_asset->file_type();
                if ($file_type && $file_type->type === 'image') {
                    $artwork_options[$episode_asset->id] = sprintf(__('Media File: %s', 'podlove'), $episode_asset->title);
                }
            }
            $wrapper->select('supports_cover_art', array('label' => __('Episode Artwork Media File', 'podlove'), 'options' => $artwork_options));
        });
        ?>
				
			</form>
		</div>	
		<?php 
    }
Пример #2
0
 private function get_chapters_object()
 {
     global $wpdb;
     // Get all posible assets with a chapter file format
     $chapter_assets = Model\EpisodeAsset::find_all_by_sql("SELECT ea.*, ft.mime_type\n\t\t\t FROM {$wpdb->prefix}podlove_episodeasset AS ea\n\t\t\t INNER JOIN {$wpdb->prefix}podlove_filetype AS ft ON ft.id = ea.file_type_id\n\t\t\t WHERE ft.type = 'chapters'\n\t\t\t ORDER BY position ASC");
     // Get IDs
     $chapter_assets_id_to_mimetype = array();
     foreach ($chapter_assets as $chapter_asset) {
         $chapter_assets_id_to_mimetype[$chapter_asset->id] = $chapter_asset->mime_type;
     }
     // Try to find attached chapter file to this episode
     $chapter_assets_ids = implode(',', array_keys($chapter_assets_id_to_mimetype));
     $chapters_file = Model\MediaFile::find_one_by_where(sprintf("episode_id = %d\n\t\t\t AND episode_asset_id IN (%s)\n\t\t\t ORDER BY FIELD(episode_asset_id, %s)", $this->episode->id, $chapter_assets_ids, $chapter_assets_ids));
     // Fallback to manual entry if no file was attached
     if (null === $chapters_file) {
         return Parser\Mp4chaps::parse($this->episode->chapters);
     }
     // Get mimetype for attached chapter file
     $mime_type = $chapter_assets_id_to_mimetype[$chapters_file->episode_asset_id];
     // Get chapters object for mine type
     switch ($mime_type) {
         case 'application/xml':
             $contents = $this->get_raw_chapters_string($chapters_file);
             $chapters = Parser\PSC::parse($contents);
             break;
         case 'application/json':
             $contents = $this->get_raw_chapters_string($chapters_file);
             $chapters = Parser\JSON::parse($contents);
             break;
         case 'text/plain':
             $contents = $this->get_raw_chapters_string($chapters_file);
             switch ($contents[0]) {
                 case '[':
                 case '{':
                     $chapters = Parser\JSON::parse($contents);
                     break;
                 case '<':
                     $chapters = Parser\PSC::parse($contents);
                     break;
                 default:
                     $chapters = Parser\Mp4chaps::parse($contents);
                     break;
             }
             break;
         default:
             $chapters = '';
     }
     // Apply filter
     return apply_filters('podlove_get_chapters_object', '' === $chapters || null === $chapters ? new Chapters() : $chapters, $mime_type, $chapters_file, $this);
 }
 private function reset_migration()
 {
     delete_option('podlove_module_migration');
     delete_option('podlove_migration');
     delete_option('podlove_migration_validation_cache');
     delete_option('podlove_asset_assignment');
     delete_option('podlove_migrated_posts_cache');
     $args = array('post_type' => 'podcast', 'posts_per_page' => -1);
     $query = new \WP_Query($args);
     while ($query->have_posts()) {
         $query->the_post();
         wp_delete_post(get_the_ID());
     }
     wp_reset_postdata();
     foreach (Model\EpisodeAsset::all() as $asset) {
         $asset->delete();
     }
     foreach (Model\Feed::all() as $feed) {
         $feed->delete();
     }
 }
Пример #4
0
 public function prepare_items()
 {
     // number of items per page
     $per_page = 10;
     // define column headers
     $columns = $this->get_columns();
     $hidden = array();
     $sortable = $this->get_sortable_columns();
     $this->_column_headers = array($columns, $hidden, $sortable);
     // retrieve data
     $data = \Podlove\Model\EpisodeAsset::all();
     // get current page
     $current_page = $this->get_pagenum();
     // get total items
     $total_items = count($data);
     // extrage page for current page only
     $data = array_slice($data, ($current_page - 1) * $per_page, $per_page);
     // add items to table
     $this->items = $data;
     // register pagination options & calculations
     $this->set_pagination_args(array('total_items' => $total_items, 'per_page' => $per_page, 'total_pages' => ceil($total_items / $per_page)));
 }
 public static function content()
 {
     global $wpdb;
     $sql = "\n\t\tSELECT\n\t\t\tp.post_status,\n\t\t\tmf.episode_id,\n\t\t\tmf.episode_asset_id,\n\t\t\tmf.size,\n\t\t\tmf.id media_file_id\n\t\tFROM\n\t\t\t`" . Model\MediaFile::table_name() . "` mf\n\t\t\tJOIN `" . Model\Episode::table_name() . "` e ON e.id = mf.`episode_id`\n\t\t\tJOIN `" . $wpdb->posts . "` p ON e.`post_id` = p.`ID`\n\t\tWHERE\n\t\t\tp.`post_type` = 'podcast'\n\t\t\tAND p.post_status in ('private', 'draft', 'publish', 'pending', 'future')\n\t\t";
     $rows = $wpdb->get_results($sql, ARRAY_A);
     $media_files = [];
     foreach ($rows as $row) {
         if (!isset($media_files[$row['episode_id']])) {
             $media_files[$row['episode_id']] = ['post_status' => $row["post_status"]];
         }
         $media_files[$row['episode_id']][$row['episode_asset_id']] = ['size' => $row['size'], 'media_file_id' => $row['media_file_id']];
     }
     $podcast = Model\Podcast::get();
     $episodes = $podcast->episodes();
     $assets = Model\EpisodeAsset::all();
     $header = [__('Episode', 'podlove')];
     foreach ($assets as $asset) {
         $header[] = $asset->title;
     }
     $header[] = __('Status', 'podlove');
     \Podlove\load_template('settings/dashboard/file_validation', ['episodes' => $episodes, 'assets' => $assets, 'media_files' => $media_files, 'header' => $header]);
 }
Пример #6
0
 /**
  * Fetch form data for EpisodeAssets multiselect.
  * 
  * @param  \Podlove\Model\Episode $episode
  * @return array
  */
 public static function episode_assets_form($episode)
 {
     $episode_assets = Model\EpisodeAsset::all();
     // field to generate option list
     $asset_options = array();
     // values for option list
     $asset_values = array();
     foreach ($episode_assets as $asset) {
         if (!($file_type = $asset->file_type())) {
             continue;
         }
         // get formats configured for this show
         $asset_options[$asset->id] = $asset->title;
         // find out which formats are active
         $asset_values[$asset->id] = NULL !== Model\MediaFile::find_by_episode_id_and_episode_asset_id($episode->id, $asset->id);
     }
     // FIXME: empty checkbox -> no file id
     // solution: when one checks the box, an AJAX request has to create and validate the file
     $episode_assets_form = array('label' => __('Media Files', 'podlove'), 'description' => '', 'options' => $asset_options, 'default' => true, 'multi_values' => $asset_values, 'multiselect_callback' => function ($asset_id) use($episode) {
         $asset = \Podlove\Model\EpisodeAsset::find_by_id($asset_id);
         $format = $asset->file_type();
         $file = \Podlove\Model\MediaFile::find_by_episode_id_and_episode_asset_id($episode->id, $asset->id);
         $attributes = array('data-template' => $asset->url_template, 'data-extension' => $format->extension, 'data-size' => is_object($file) ? $file->size : 0, 'data-episode-asset-id' => $asset->id, 'data-episode-id' => $episode->id);
         if ($file) {
             $attributes['data-id'] = $file->id;
         }
         $out = '';
         foreach ($attributes as $key => $value) {
             $out .= sprintf('%s="%s" ', $key, $value);
         }
         return $out;
     });
     if (empty($asset_options)) {
         $episode_assets_form['description'] = sprintf('<span style="color: red">%s</span>', __('You need to configure feeds for this show. No feeds, no fun.', 'podlove')) . ' ' . sprintf('<a href="%s">%s</a>', admin_url('admin.php?page=podlove_shows_settings_handle&action=edit&show=' . $show->id), __('Edit this show', 'podlove'));
     }
     return $episode_assets_form;
 }
Пример #7
0
 public function update_asset_position()
 {
     $asset_id = (int) $_REQUEST['asset_id'];
     $position = (double) $_REQUEST['position'];
     Model\EpisodeAsset::find_by_id($asset_id)->update_attributes(array('position' => $position));
     die;
 }
Пример #8
0
    public function modal_box_html()
    {
        $podcast = Model\Podcast::get_instance();
        $episode_assets = Model\EpisodeAsset::all();
        $episode_asset = $episode_assets[0];
        $podcast_data = array('slug' => $podcast->slug, 'name' => $podcast->title, 'next_number' => $this->guess_next_episode_id_for_show(), 'base_url' => $podcast->media_file_base_uri, 'episode_asset' => array('template' => $episode_asset->url_template));
        ?>
		<div id="new-episode-modal" class="hidden wrap" title="Create New Episode">
			<div class="hidden" id="new-episode-podcast-data"><?php 
        echo json_encode($podcast_data);
        ?>
</div>
			<p>
				<div id="titlediv">
					<p>
						<strong>Episode Number</strong>
						<input type="text" name="episode_number" value="<?php 
        echo $this->guess_next_episode_id_for_show();
        ?>
" class="really-huge-text episode_number" autocomplete="off">
					</p>
					<p>
						<strong>Episode Title</strong>
						<input type="text" name="episode_title" value="" class="really-huge-text episode_title" autocomplete="off">
					</p>
					<p class="media_file_info result">
						<strong>Media Files</strong>
						<span class="url">Loading ...</span>
					</p>
					<p class="post_info result">
						<strong>Post Title</strong>
						<span class="post_title" data-template="<?php 
        echo $this->get_module_option('title_template', '%podcast_slug%%episode_number% %episode_title%');
        ?>
">Loading ...</span>
					</p>
				</div>
			</p>
		</div>

		<style type="text/css">
		#new-episode-modal .media_file_info, #new-episode-modal .post_info {
			color: #666;
		}

		#new-episode-modal p.result strong {
			display: inline-block;
			width: 115px;
		}

		#episode_file_slug {
			cursor: pointer;
			font-style: italic;
			color: black;
		}

		#episode_file_slug input {
			width: 70px;
			-webkit-border-radius: 3px;
			border-radius: 3px;
			border-width: 1px;
			border-style: solid;
			border-color: #DFDFDF;
		}

		input.really-huge-text {
			padding: 3px 8px;
			font-size: 1.7em;
			line-height: 100%;
			width: 100%;
		}
		</style>
		<?php 
    }
    /**
     * Fetch form data for EpisodeAssets multiselect.
     * 
     * @param  \Podlove\Model\Episode $episode
     * @return array
     */
    public static function episode_assets_form($episode)
    {
        $episode_assets = Model\EpisodeAsset::all();
        // field to generate option list
        $asset_options = array();
        // values for option list
        $asset_values = array();
        foreach ($episode_assets as $asset) {
            if (!($file_type = $asset->file_type())) {
                continue;
            }
            // get formats configured for this show
            $asset_options[$asset->id] = $asset->title;
            // find out which formats are active
            $asset_values[$asset->id] = NULL !== Model\MediaFile::find_by_episode_id_and_episode_asset_id($episode->id, $asset->id);
        }
        // FIXME: empty checkbox -> no file id
        // solution: when one checks the box, an AJAX request has to create and validate the file
        $episode_assets_form = array('label' => __('Media Files', 'podlove'), 'description' => '', 'options' => $asset_options, 'default' => true, 'multi_values' => $asset_values, 'before' => function () {
            ?>
				<table class='media_file_table' border="0" cellspacing="0">
					<tr>
						<th><?php 
            echo __('Enable', 'podlove');
            ?>
</th>
						<th><?php 
            echo __('Asset', 'podlove');
            ?>
</th>
						<th><?php 
            echo __('Asset File Name', 'podlove');
            ?>
</th>
						<th><?php 
            echo __('Filesize', 'podlove');
            ?>
</th>
						<th><?php 
            echo __('Status', 'podlove');
            ?>
</th>
						<th></th>
					</tr>
				<?php 
        }, 'after' => function () {
            ?>
				</table>
				<p>
					<span class="description">
						<?php 
            echo __('Media File Base URL', 'podlove') . ': ' . \Podlove\Model\Podcast::get()->media_file_base_uri;
            ?>
					</span>
				</p>
				<?php 
        }, 'around_each' => function ($callback) {
            ?>
				<tr class="media_file_row">
					<td class="enable">
					</td>
					<td class="asset">
						<?php 
            call_user_func($callback);
            ?>
					</td>
					<td class="url"></td>
					<td class="size"></td>
					<td class="status"></td>
					<td class="update"></td>
				</tr>
				<?php 
        }, 'multiselect_callback' => function ($asset_id) use($episode) {
            $asset = \Podlove\Model\EpisodeAsset::find_by_id($asset_id);
            $format = $asset->file_type();
            $file = \Podlove\Model\MediaFile::find_by_episode_id_and_episode_asset_id($episode->id, $asset->id);
            $size = is_object($file) ? (int) $file->size : 0;
            if ($size === 1) {
                $size = "unknown";
            }
            $attributes = array('data-template' => \Podlove\Model\Podcast::get()->get_url_template(), 'data-size' => $size, 'data-episode-asset-id' => $asset->id, 'data-episode-id' => $episode->id, 'data-file-url' => is_object($file) ? $file->get_file_url() : '');
            if ($file) {
                $attributes['data-id'] = $file->id;
            }
            $out = '';
            foreach ($attributes as $key => $value) {
                $out .= sprintf('%s="%s" ', $key, $value);
            }
            return $out;
        });
        if (empty($asset_options)) {
            $episode_assets_form['description'] = sprintf('<span style="color: red">%s</span>', __('You need to configure assets for this show. No assets, no fun.', 'podlove')) . ' ' . sprintf('<a href="%s">%s</a>', admin_url('admin.php?page=podlove_episode_assets_settings_handle'), __('Configure Assets', 'podlove'));
        }
        return $episode_assets_form;
    }
Пример #10
0
/**
 * Find and run migration for given version number.
 *
 * @todo  move migrations into separate files
 * 
 * @param  int $version
 */
function run_migrations_for_version($version)
{
    global $wpdb;
    switch ($version) {
        case 2:
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `chapters` TEXT AFTER `cover_art`', \Podlove\Model\Release::table_name());
            $wpdb->query($sql);
            break;
        case 3:
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `format` VARCHAR(255) AFTER `slug`', \Podlove\Model\Feed::table_name());
            $wpdb->query($sql);
            break;
        case 4:
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `title` VARCHAR(255) AFTER `id`', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            break;
        case 5:
            \Podlove\Modules\Base::activate('podlove_web_player');
            break;
        case 6:
            // title column is "int" for some people. this migration fixes that
            $sql = sprintf('SHOW COLUMNS FROM `wp_podlove_medialocation` WHERE Field = "title"', \Podlove\Model\EpisodeAsset::table_name());
            $row = $wpdb->get_row($sql);
            if (strtolower(substr($row->Type, 0, 3)) === 'int') {
                $wpdb->query(sprintf('UPDATE `%s` SET title = NULL', \Podlove\Model\EpisodeAsset::table_name()));
                $wpdb->query(sprintf('ALTER TABLE `%s` MODIFY COLUMN `title` VARCHAR(255)', \Podlove\Model\EpisodeAsset::table_name()));
            }
            break;
        case 7:
            // move language from feed to show
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `language` VARCHAR(255) AFTER `summary`', \Podlove\Model\Show::table_name());
            $wpdb->query($sql);
            $sql = sprintf('ALTER TABLE `%s` DROP COLUMN `language`', \Podlove\Model\Feed::table_name());
            $wpdb->query($sql);
            break;
        case 8:
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `supports_cover_art` INT', \Podlove\Model\Show::table_name());
            $wpdb->query($sql);
            break;
        case 9:
            // huge architecture migration
            // assume first show will be blueprint for the podcast
            $show = $wpdb->get_row(sprintf('SELECT * FROM %s LIMIT 1', $wpdb->prefix . 'podlove_show'), ARRAY_A);
            $show_id = $show['id'];
            // On my local machine the migration runs twice.
            // This is a quick fix. caveat: someone who has no show defined
            // will need to uninstall the plugin. That seems acceptable.
            if (!$show_id) {
                return;
            }
            // all releases of this show will be converted to episodes
            $releases = $wpdb->get_results(sprintf('
					SELECT
						E.post_id, R.episode_id, R.active, R.enable, R.slug, R.duration, R.cover_art, R.chapters
					FROM 
						%s R
						INNER JOIN %s E ON R.episode_id = E.id
					WHERE
						R.show_id = "%s"
					', $wpdb->prefix . 'podlove_release', $wpdb->prefix . 'podlove_episode', $show_id), ARRAY_A);
            // write show settings to podcast
            $podcast = \Podlove\Model\Podcast::get_instance();
            foreach ($show as $key => $value) {
                $podcast->{$key} = $value;
            }
            $podcast->save();
            // rebuild show table
            \Podlove\Model\Show::destroy();
            \Podlove\Model\Show::build();
            // rebuild episodes table
            \Podlove\Model\Episode::destroy();
            \Podlove\Model\Episode::build();
            foreach ($releases as $release) {
                $episode = new \Podlove\Model\Episode();
                foreach ($release as $key => $value) {
                    if (!in_array($key, array('episode_id'))) {
                        $episode->{$key} = $value;
                    }
                }
                $episode->save();
            }
            // clean feed table
            $sql = sprintf('DELETE FROM `%s` WHERE `show_id` != "%s"', \Podlove\Model\Feed::table_name(), $show_id);
            $wpdb->query($sql);
            $sql = sprintf('ALTER TABLE `%s` DROP COLUMN `show_id`', \Podlove\Model\Feed::table_name());
            $wpdb->query($sql);
            // fix mediafile table
            $sql = sprintf('ALTER TABLE `%s` CHANGE `release_id` `episode_id` INT', \Podlove\Model\MediaFile::table_name());
            $wpdb->query($sql);
            // remove suffix
            $sql = sprintf('ALTER TABLE `%s` DROP COLUMN `suffix`', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            // add more default formats
            $default_formats = array(array('name' => 'PDF Document', 'type' => 'ebook', 'mime_type' => 'application/pdf', 'extension' => 'pdf'), array('name' => 'ePub Document', 'type' => 'ebook', 'mime_type' => 'application/epub+zip', 'extension' => 'epub'), array('name' => 'PNG Image', 'type' => 'image', 'mime_type' => 'image/png', 'extension' => 'png'), array('name' => 'JPEG Image', 'type' => 'image', 'mime_type' => 'image/jpeg', 'extension' => 'jpg'));
            foreach ($default_formats as $format) {
                $f = new Model\FileType();
                foreach ($format as $key => $value) {
                    $f->{$key} = $value;
                }
                $f->save();
            }
            // update assistant
            $assistant = \Podlove\Modules\EpisodeAssistant\Episode_Assistant::instance();
            $template = $assistant->get_module_option('title_template');
            $template = str_replace('%show_slug%', '%podcast_slug%', $template);
            $assistant->update_module_option('title_template', $template);
            // update media locations
            $media_locations = \Podlove\Model\EpisodeAsset::all();
            foreach ($media_locations as $media_location) {
                $media_location->url_template = str_replace('%suffix%', '', $media_location->url_template);
                $media_location->save();
            }
            break;
        case 10:
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `summary` TEXT', \Podlove\Model\Episode::table_name());
            $wpdb->query($sql);
            break;
        case 11:
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `downloadable` INT', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            break;
        case 12:
            $sql = sprintf('UPDATE `%s` SET `downloadable` = 1', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            break;
        case 13:
            $opus = array('name' => 'Opus Audio', 'type' => 'audio', 'mime_type' => 'audio/opus', 'extension' => 'opus');
            $f = new \Podlove\Model\FileType();
            foreach ($opus as $key => $value) {
                $f->{$key} = $value;
            }
            $f->save();
            break;
        case 14:
            $sql = sprintf('ALTER TABLE `%s` RENAME TO `%s`', $wpdb->prefix . 'podlove_medialocation', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            break;
        case 15:
            $sql = sprintf('ALTER TABLE `%s` CHANGE `media_location_id` `episode_asset_id` INT', \Podlove\Model\MediaFile::table_name());
            $wpdb->query($sql);
            break;
        case 16:
            $sql = sprintf('ALTER TABLE `%s` CHANGE `media_location_id` `episode_asset_id` INT', \Podlove\Model\Feed::table_name());
            $wpdb->query($sql);
            break;
        case 17:
            $sql = sprintf('ALTER TABLE `%s` RENAME TO `%s`', $wpdb->prefix . 'podlove_mediaformat', \Podlove\Model\FileType::table_name());
            $wpdb->query($sql);
            break;
        case 18:
            $sql = sprintf('ALTER TABLE `%s` CHANGE `media_format_id` `file_type_id` INT', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            break;
    }
}
Пример #11
0
 public function __construct()
 {
     $errors =& $this->errors;
     $notices =& $this->notices;
     $this->fields = array('site' => array('title' => 'Website', 'callback' => function () {
         return get_site_url();
     }), 'php_version' => array('title' => 'PHP Version', 'callback' => function () {
         return phpversion();
     }), 'wp_version' => array('title' => 'WordPress Version', 'callback' => function () {
         return get_bloginfo('version');
     }), 'podlove_version' => array('title' => 'Publisher Version', 'callback' => function () {
         return \Podlove\get_plugin_header('Version');
     }), 'player_version' => array('title' => 'Web Player Version', 'callback' => function () {
         if (!defined('PODLOVEWEBPLAYER_DIR')) {
             return 'no web player found';
         }
         $pwp_file = PODLOVEWEBPLAYER_DIR . 'podlove-web-player.php';
         if (!is_readable($pwp_file)) {
             return 'not readable';
         }
         $plugin_data = \get_plugin_data($pwp_file);
         return $plugin_data['Version'];
     }), 'twig_version' => array('title' => 'Twig Version', 'callback' => function () {
         return \Twig_Environment::VERSION;
     }), 'open_basedir' => array('callback' => function () use(&$notices) {
         $open_basedir = trim(ini_get('open_basedir'));
         if ($open_basedir != '.') {
             $notices[] = 'The PHP setting "open_basedir" is not empty. This is incompatible with curl, a library required by Podlove Publisher. We have a workaround in place but it is preferred to fix the issue. Please ask your hoster to unset "open_basedir".';
         }
         if ($open_basedir) {
             return $open_basedir;
         } else {
             return 'ok';
         }
     }), 'curl' => array('title' => 'curl Version', 'callback' => function () use(&$errors) {
         $module_loaded = in_array('curl', get_loaded_extensions());
         $function_disabled = stripos(ini_get('disable_functions'), 'curl_exec') !== false;
         $out = '';
         if ($module_loaded) {
             $curl = curl_version();
             $out .= $curl['version'];
         } else {
             $out .= 'EXTENSION MISSING';
             $errors[] = 'curl extension is not loaded';
         }
         if ($function_disabled) {
             $out .= ' | curl_exec is disabled';
             $errors[] = 'curl_exec is disabled';
         }
         return $out;
     }), 'iconv' => array('callback' => function () use(&$errors) {
         $iconv_available = function_exists('iconv');
         if (!$iconv_available) {
             $errors[] = 'You need to install/activate php5-iconv';
         }
         return $iconv_available ? "available" : "MISSING";
     }), 'simplexml' => array('callback' => function () use(&$errors) {
         if (!($simplexml = in_array('SimpleXML', get_loaded_extensions()))) {
             $errors[] = 'You need to install/activate the PHP SimpleXML module';
         }
         return $simplexml ? 'ok' : 'missing!';
     }), 'max_execution_time' => array('callback' => function () {
         return ini_get('max_execution_time');
     }), 'upload_max_filesize' => array('callback' => function () {
         return ini_get('upload_max_filesize');
     }), 'memory_limit' => array('callback' => function () {
         return ini_get('memory_limit');
     }), 'disable_classes' => array('callback' => function () {
         return ini_get('disable_classes');
     }), 'disable_functions' => array('callback' => function () {
         return ini_get('disable_functions');
     }), 'permalinks' => array('callback' => function () use(&$errors) {
         $permalinks = \get_option('permalink_structure');
         if (!$permalinks) {
             $errors[] = sprintf(__('You are using the default WordPress permalink structure. This may cause problems with some podcast clients. Go to %s and set it to anything but default (for example "Post name").', 'podlove'), admin_url('options-permalink.php'));
             return __("\"non-pretty\" Permalinks: Please change permalink structure", 'podlove');
         }
         return "ok ({$permalinks})";
     }), 'podlove_permalinks' => array('callback' => function () use(&$errors) {
         if (\Podlove\get_setting('website', 'use_post_permastruct') == 'on') {
             return 'ok';
         }
         if (stristr(\Podlove\get_setting('website', 'custom_episode_slug'), '%podcast%') === FALSE) {
             $website_options = get_option('podlove_website');
             $website_options['use_post_permastruct'] = 'on';
             update_option('podlove_website', $website_options);
         }
         return 'ok';
     }), 'podcast_settings' => array('callback' => function () use(&$errors) {
         $out = '';
         $podcast = Model\Podcast::get();
         if (!$podcast->title) {
             $error = __('Your podcast needs a title.', 'podlove');
             $errors[] = $error;
             $out .= $error;
         }
         if (!$podcast->media_file_base_uri) {
             $error = __('Your podcast needs an upload location for file storage.', 'podlove');
             $errors[] = $error;
             $out .= $error;
         }
         if (!$out) {
             $out = "ok";
         }
         return $out;
     }), 'web_player' => array('callback' => function () use(&$errors) {
         foreach (get_option('podlove_webplayer_formats', array()) as $_ => $media_types) {
             foreach ($media_types as $extension => $asset_id) {
                 if ($asset_id) {
                     return "ok";
                 }
             }
         }
         $error = __('You need to assign at least one asset to the web player.', 'podlove');
         $errors[] = $error;
         return $error;
     }), 'podlove_cache' => array('callback' => function () {
         return \Podlove\Cache\TemplateCache::is_enabled() ? 'on' : 'off';
     }), 'assets' => array('callback' => function () {
         $assets = array();
         foreach (\Podlove\Model\EpisodeAsset::all() as $asset) {
             $file_type = $asset->file_type();
             $assets[] = array('extension' => $file_type->extension, 'mime_type' => $file_type->mime_type);
         }
         return "\n\t" . implode("\n\t", array_map(function ($asset) {
             return str_pad($asset['extension'], 7) . $asset['mime_type'];
         }, $assets));
     }));
     $this->fields = apply_filters('podlove_system_report_fields', $this->fields);
     $this->run();
 }
Пример #12
0
 public function refetch_files()
 {
     $valid_files = array();
     foreach (EpisodeAsset::all() as $asset) {
         if ($file = MediaFile::find_by_episode_id_and_episode_asset_id($this->id, $asset->id)) {
             $file->determine_file_size();
             $file->save();
             if ($file->is_valid()) {
                 $valid_files[] = $file->id;
             }
         }
     }
     if (empty($valid_files) && get_post_status($this->post_id) == 'publish') {
         Log::get()->addAlert('All assets for this episode are invalid!', array('episode_id' => $this->id));
     }
 }
    public function template()
    {
        // load already migrated posts
        $migrated_posts_cache = get_option('podlove_migrated_posts_cache', array());
        // then begin to migrate
        $migration_settings = get_option('podlove_migration', array());
        // Basic Podcast Settings
        $podcast = Model\Podcast::get();
        $podcast->title = $migration_settings['podcast']['title'];
        $podcast->subtitle = $migration_settings['podcast']['subtitle'];
        $podcast->summary = $migration_settings['podcast']['summary'];
        $podcast->media_file_base_uri = \Podlove\Modules\Migration\get_media_file_base_url();
        // harvest low hanging podPress fruits
        if ($podPress_config = get_option('podPress_config')) {
            if (isset($podPress_config['iTunes']['image']) && !$podcast->cover_image) {
                $podcast->cover_image = $podPress_config['iTunes']['image'];
            }
        }
        // harvest low hanging PowerPress fruits
        if ($powerPress_config = get_option('powerpress_feed')) {
            if (isset($powerPress_config['itunes_image']) && !$podcast->cover_image) {
                $podcast->cover_image = $powerPress_config['itunes_image'];
            }
            if (isset($powerPress_config['itunes_cat_1']) && !$podcast->category_1) {
                $podcast->category_1 = $powerPress_config['itunes_cat_1'];
            }
            if (isset($powerPress_config['itunes_cat_2']) && !$podcast->category_2) {
                $podcast->category_2 = $powerPress_config['itunes_cat_2'];
            }
            if (isset($powerPress_config['itunes_cat_3']) && !$podcast->category_3) {
                $podcast->category_3 = $powerPress_config['itunes_cat_3'];
            }
        }
        $podcast->save();
        // Create Template
        $template = Model\Template::find_one_by_title('default');
        if (!$template) {
            $template = new Model\Template();
            $template->title = 'default';
            $template->content = <<<EOT
{{ episode.player }}
[podlove-episode-downloads]
EOT;
            $template->save();
        }
        $template_assignment = Model\TemplateAssignment::get_instance();
        if ($template_assignment->has_property($migration_settings['cleanup']['template'])) {
            $template_assignment->{$migration_settings}['cleanup']['template'] = $template->id;
            $template_assignment->save();
        }
        // Create Assets
        $assets = array();
        foreach ($migration_settings['file_types'] as $file_type_id => $_) {
            $file_type = Model\FileType::find_one_by_id($file_type_id);
            $is_image = in_array($file_type->extension, array('png', 'jpg', 'jpeg', 'gif'));
            $asset = Model\EpisodeAsset::find_one_by_file_type_id($file_type_id);
            if (!$asset) {
                $asset = new Model\EpisodeAsset();
                $asset->title = $file_type->name;
                $asset->file_type_id = $file_type_id;
                $asset->downloadable = !$is_image;
                $asset->save();
            }
            $assets[] = $asset;
            if ($is_image) {
                $asset_assignments = get_option('podlove_asset_assignment', array());
                if (!$asset_assignments['image']) {
                    $asset_assignments['image'] = $asset->id;
                    update_option('podlove_asset_assignment', $asset_assignments);
                }
            }
            // create feeds
            if (stripos($file_type->mime_type, 'audio') !== false) {
                $feed = Model\Feed::find_one_by_episode_asset_id($asset->id);
                if (!$feed) {
                    $feed = new Model\Feed();
                    $feed->episode_asset_id = $asset->id;
                    $feed->name = $file_type->name;
                    $feed->title = $file_type->name;
                    $feed->slug = $file_type->extension;
                    $feed->format = 'rss';
                    $feed->enable = true;
                    $feed->discoverable = true;
                    $feed->limit_items = -1;
                    $feed->save();
                }
            }
            // set web player settings
            $webplayer_formats = get_option('podlove_webplayer_formats', array());
            if (!isset($webplayer_formats['audio'])) {
                $webplayer_formats['audio'] = array();
            }
            if (stripos($file_type->mime_type, 'audio/mpeg') !== false) {
                $webplayer_formats['audio']['mp3'] = $asset->id;
            } elseif (stripos($file_type->mime_type, 'audio/mp4') !== false) {
                $webplayer_formats['audio']['mp4'] = $asset->id;
            } elseif (stripos($file_type->mime_type, 'audio/ogg') !== false) {
                $webplayer_formats['audio']['ogg'] = $asset->id;
            } elseif (stripos($file_type->mime_type, 'audio/opus') !== false) {
                $webplayer_formats['audio']['opus'] = $asset->id;
            }
            update_option('podlove_webplayer_formats', $webplayer_formats);
        }
        // flush rules after migration
        set_transient('podlove_needs_to_flush_rewrite_rules', true);
        ?>
		
		<form action="" method="POST">
			<input type="submit" name="prev" class="btn" value="<?php 
        echo __('Back', 'podlove');
        ?>
">
			<input type="submit" name="next" id="continue_to_finish_button" class="btn btn-primary disabled pull-right" value="<?php 
        echo __('Continue to last step', 'podlove');
        ?>
">
		</form>

		<div class="row-fluid">
			<div class="span12">
				<h3 id="migration-header">Migrating <small></small></h3>
			</div>
		</div>

		<div class="progress progress-striped active" id="migration_progress">
			<div class="bar" style="width:0%"></div>
		</div>

		<p>
			<input type="button" id="start_migration_button" class="btn btn-primary" value="<?php 
        echo __('Start Migration', 'podlove');
        ?>
">
			Starting the migration creates the actual episodes one by one.			
		</p>

		<table class="table table-condensed" id="posts_to_migrate">
			<thead>
				<tr>
					<th>Status</th>
					<th>Episode</th>
				</tr>
			</thead>
			<tbody>
				<?php 
        $migrated_post_ids = array_keys($migrated_posts_cache);
        ?>
				<?php 
        foreach ($migration_settings['episodes'] as $post_id => $_) {
            ?>
					<?php 
            $done = in_array($post_id, $migrated_post_ids);
            ?>
					<tr data-post-id="<?php 
            echo $post_id;
            ?>
" <?php 
            echo $done ? 'class="done"' : '';
            ?>
>
						<td class="status">
							<span class="waiting" <?php 
            echo !$done ? '' : 'style="display:none"';
            ?>
>not yet migrated</span>
							<span class="migrating" style="display:none"><i class="podlove-icon-spinner rotate"></i></span>
							<span class="done" <?php 
            echo $done ? '' : 'style="display:none"';
            ?>
><i class="podlove-icon-ok"></i></span>
						</td>
						<td class="episode">
							<?php 
            if ($done) {
                ?>
								<a href="<?php 
                echo get_edit_post_link($migrated_posts_cache[$post_id]);
                ?>
" target="_blank">
									<?php 
                echo get_the_title($post_id);
                ?>
								</a>
							<?php 
            } else {
                ?>
								<?php 
                echo get_the_title($post_id);
                ?>
							<?php 
            }
            ?>
						</td>
					</tr>
				<?php 
        }
        ?>
			</tbody>
		</table>

		<script type="text/javascript">
		jQuery(function($) {
			var posts_to_migrate = $("#posts_to_migrate tbody tr").length;

			$("#continue_to_finish_button").hide();

			function update_migration_progress_bar() {
				var posts_done = $("#posts_to_migrate tbody tr.done").length;
				progress = Math.round(posts_done / posts_to_migrate * 100)
				$("#migration_progress .bar")
					.css("width", progress + "%")
					.html(posts_done + " / " + posts_to_migrate);

				if ( progress == 100 ) {
					$("#migration_progress")
						.removeClass("active")
						.addClass("progress-success")
						.find(".bar").html("Done! Whoop whoop!");

					$("#migration-header small").html('');
					$("#start_migration_button").addClass("disabled");
					$("#continue_to_finish_button").removeClass("disabled").show();
				}
			};

			function podlove_migrate_one_post() {
				$("#posts_to_migrate tbody tr:not(.done):first").each(function() {
					var post_id = $(this).data("post-id")
					    that = $(this),
					    episode_title = $(".episode", that).html();

					$("#migration-header small").html(episode_title);

					var data = {
						action: 'podlove-migrate-post',
						post_id: post_id
					};

					$.ajax({
						url: ajaxurl,
						data: data,
						dataType: 'json',
						beforeSend: function(jqXHR, settings) {
							$(".waiting, .done", that).hide();
							$(".migrating", that).show();
						},
						success: function(result) {
							var episode_url = result.url;

							$(".waiting, .migrating", that).hide();
							$(".done", that).show();
							that.addClass("done");

							// add link
							$(".episode", that).html('<a href="' + episode_url + '" target="_blank">' + episode_title + '</a>')

							// update progress bar
							update_migration_progress_bar();

							// continue
							podlove_migrate_one_post();
						}
					});
				});
			}

			$("#start_migration_button").on("click", function(){
				if (!$(this).hasClass("disabled")) {
					$(this).addClass("disabled");
					podlove_migrate_one_post();
				}
			});
			update_migration_progress_bar();
		});
		</script>
		<?php 
    }
Пример #14
0
 /**
  * Get playable files for player, based on episode and player assignments.
  * 
  * @param  array  $formats      array of formats like mp3, mp3, ogg, opus, webm
  * @param  string $media_type   audio or video
  * @return array of \Podlove\Model\MediaFile
  */
 private function get_playable_files($formats, $media_type)
 {
     $playable_files = array();
     foreach ($formats as $format) {
         if (!isset($this->player_format_assignments[$media_type][$format])) {
             continue;
         }
         $episode_asset = EpisodeAsset::find_by_id($this->player_format_assignments[$media_type][$format]);
         if (!$episode_asset) {
             continue;
         }
         $media_file = MediaFile::find_by_episode_id_and_episode_asset_id($this->episode->id, $episode_asset->id);
         if ($media_file && $media_file->is_valid()) {
             $playable_files[] = $media_file;
         }
     }
     return $playable_files;
 }
Пример #15
0
    public static function validate_podcast_files()
    {
        $podcast = Model\Podcast::get_instance();
        $podcast_warnings = self::get_podcast_setting_warnings();
        if (!in_array('curl', get_loaded_extensions())) {
            ?>
			<div class="error">
				<p>
					<strong>ERROR: </strong>You need the <strong>curl PHP extension</strong> for Podlove to run properly.
					<br>
					If you think you can do it yourself, have a look at <a href="http://stackoverflow.com/questions/1347146/how-to-enable-curl-in-php">these instructions on how to enable curl in PHP</a>.
				</p>
			</div>
			<?php 
        }
        ?>
		<div id="validation">

			<?php 
        if (count($podcast_warnings)) {
            ?>
				<style type="text/css">
				#podcast_warnings {
					color: #333333;
					background-color: #FFEBE8;
					border: 1px solid #CC0000;
					border-radius: 3px;
					padding: 0.4em 1.0em;
					margin: 10px 0px;
				}
				#podcast_warnings h4 {
					margin: 10px 0px;
				}
				</style>
				<div id="podcast_warnings">
					<h4><?php 
            echo __('Critical Notes');
            ?>
</h4>
					<?php 
            foreach ($podcast_warnings as $warning) {
                ?>
						<div class="line">
							<?php 
                echo $warning;
                ?>
							<a href="<?php 
                echo admin_url('admin.php?page=podlove_settings_podcast_handle');
                ?>
">
								<?php 
                echo __('go fix it', 'podlove');
                ?>
							</a>
						</div>
					<?php 
            }
            ?>
				</div>
			<?php 
        }
        ?>

			<?php 
        $episodes = Model\Episode::all();
        $assets = Model\EpisodeAsset::all();
        $header = array(__('Episode', 'podlove'));
        foreach ($assets as $asset) {
            $header[] = $asset->title;
        }
        $header[] = __('Status', 'podlove');
        // $header[] = ''; // buttons
        define('ASSET_STATUS_OK', '<span style="color: green">✓</span>');
        define('ASSET_STATUS_INACTIVE', '—');
        define('ASSET_STATUS_ERROR', '<span style="color: red">!!!</span>');
        ?>

			<h4><?php 
        echo $podcast->title;
        ?>
</h4>

			<table>
				<thead>
					<tr>
						<?php 
        foreach ($header as $column_head) {
            ?>
							<th><?php 
            echo $column_head;
            ?>
</th>
						<?php 
        }
        ?>
					</tr>
				</thead>
				<tbody>
					<?php 
        foreach ($episodes as $episode) {
            ?>
						<?php 
            $post_id = $episode->post_id;
            $post = get_post($post_id);
            // skip deleted podcasts
            if (!in_array($post->post_status, array('draft', 'publish'))) {
                continue;
            }
            // skip versions
            if ($post->post_type != 'podcast') {
                continue;
            }
            ?>
						<tr>
							<td>
								<a href="<?php 
            echo get_edit_post_link($episode->post_id);
            ?>
"><?php 
            echo $episode->slug;
            ?>
</a>
							</td>
							<?php 
            $media_files = $episode->media_files();
            ?>
							<?php 
            foreach ($assets as $asset) {
                ?>
								<td style="text-align: center; font-weight: bold; font-size: 20px">
									<?php 
                $files = array_filter($media_files, function ($file) use($asset) {
                    return $file->episode_asset_id == $asset->id;
                });
                $file = array_pop($files);
                if (!$file) {
                    echo ASSET_STATUS_INACTIVE;
                } elseif ($file->size > 0) {
                    echo ASSET_STATUS_OK;
                } else {
                    echo ASSET_STATUS_ERROR;
                }
                ?>
								</td>
							<?php 
            }
            ?>
							<td>
								<?php 
            echo $post->post_status;
            ?>
							</td>
							<!-- <td>buttons</td> -->
						</tr>
					<?php 
        }
        ?>
				</tbody>
			</table>
		</div>

		<style type="text/css">
		#validation h4 {
			font-size: 20px;
		}

		#validation .episode {
			margin: 0 0 15px 0;
		}

		#validation .slug {
			font-size: 18px;
			margin: 0 0 5px 0;
		}

		#validation .warning {
			color: maroon;
		}

		#validation .error {
			color: red;
		}
		</style>
		<?php 
    }
 private function edit_template()
 {
     $episode_asset = \Podlove\Model\EpisodeAsset::find_by_id($_REQUEST['episode_asset']);
     echo '<h3>' . sprintf(__('Edit Episode Asset: %s', 'podlove'), $episode_asset->title) . '</h3>';
     $this->form_template($episode_asset, 'save');
 }
Пример #17
0
 private function form_template($feed, $action, $button_text = NULL)
 {
     $form_args = array('context' => 'podlove_feed', 'hidden' => array('feed' => $feed->id, 'action' => $action));
     \Podlove\Form\build_for($feed, $form_args, function ($form) {
         $wrapper = new \Podlove\Form\Input\TableWrapper($form);
         $feed = $form->object;
         $episode_assets = \Podlove\Model\EpisodeAsset::all();
         $assets = array();
         foreach ($episode_assets as $asset) {
             $assets[$asset->id] = $asset->title;
         }
         $wrapper->string('name', array('label' => __('Feed Title', 'podlove'), 'description' => __('Some podcast clients may display this title to describe the feed content.', 'podlove'), 'html' => array('class' => 'regular-text required')));
         $wrapper->checkbox('discoverable', array('label' => __('Discoverable?', 'podlove'), 'description' => __('Embed a meta tag into the head of your site so browsers and feed readers will find the link to the feed.', 'podlove'), 'default' => true));
         // TODO: update url
         $wrapper->string('slug', array('label' => __('Slug', 'podlove'), 'description' => $feed ? sprintf(__('Feed identifier. URL: %s', 'podlove'), $feed->get_subscribe_url()) : '', 'html' => array('class' => 'regular-text required')));
         $wrapper->radio('format', array('label' => __('Format', 'podlove'), 'options' => array('rss' => 'RSS', 'atom' => 'Atom'), 'default' => 'rss'));
         $wrapper->select('episode_asset_id', array('label' => __('Episode Media File', 'podlove'), 'options' => $assets, 'html' => array('class' => 'required')));
         $wrapper->string('itunes_feed_id', array('label' => __('iTunes Feed ID', 'podlove'), 'description' => __('Is used to generate a link to the iTunes directory.', 'podlove'), 'html' => array('class' => 'regular-text')));
         // todo: add PING url; see feedburner doc
         $wrapper->string('redirect_url', array('label' => __('Redirect Url', 'podlove'), 'description' => __('e.g. Feedburner URL', 'podlove'), 'html' => array('class' => 'regular-text')));
         $wrapper->checkbox('enable', array('label' => __('Allow Submission to Directories', 'podlove'), 'description' => __('Allow this feed to appear in podcast directories.', 'podlove'), 'default' => true));
         // TODO: choose description format: empty, simple, full-force
         $wrapper->checkbox('show_description', array('label' => __('Include Description?', 'podlove'), 'description' => __('You may want to hide the episode descriptions to reduce the feed file size.', 'podlove'), 'default' => true));
         // todo include summary?
         $wrapper->string('limit_items', array('label' => __('Limit Items', 'podlove'), 'description' => __('A feed only displays the most recent episodes. Define the amount. Leave empty to use the WordPress default.', 'podlove'), 'html' => array('class' => 'regular-text')));
     });
 }
 /**
  * Return real file URL
  *
  * For public facing URLs, use ::get_public_file_url().
  *
  * @return string
  */
 public function get_file_url()
 {
     return $this->with_blog_scope(function () {
         $podcast = Podcast::get();
         $episode = $this->episode();
         $episode_asset = EpisodeAsset::find_by_id($this->episode_asset_id);
         $file_type = FileType::find_by_id($episode_asset->file_type_id);
         if (!$episode_asset || !$file_type || !$episode) {
             return '';
         }
         $template = $podcast->get_url_template();
         $template = apply_filters('podlove_file_url_template', $template);
         $template = str_replace('%media_file_base_url%', trailingslashit($podcast->media_file_base_uri), $template);
         $template = str_replace('%episode_slug%', \Podlove\slugify($episode->slug), $template);
         $template = str_replace('%suffix%', $episode_asset->suffix, $template);
         $template = str_replace('%format_extension%', $file_type->extension, $template);
         return trim($template);
     });
 }
Пример #19
0
/**
 * Find and run migration for given version number.
 *
 * @todo  move migrations into separate files
 * 
 * @param  int $version
 */
function run_migrations_for_version($version)
{
    global $wpdb;
    switch ($version) {
        case 10:
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `summary` TEXT', \Podlove\Model\Episode::table_name());
            $wpdb->query($sql);
            break;
        case 11:
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `downloadable` INT', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            break;
        case 12:
            $sql = sprintf('UPDATE `%s` SET `downloadable` = 1', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            break;
        case 13:
            $opus = array('name' => 'Opus Audio', 'type' => 'audio', 'mime_type' => 'audio/opus', 'extension' => 'opus');
            $f = new \Podlove\Model\FileType();
            foreach ($opus as $key => $value) {
                $f->{$key} = $value;
            }
            $f->save();
            break;
        case 14:
            $sql = sprintf('ALTER TABLE `%s` RENAME TO `%s`', $wpdb->prefix . 'podlove_medialocation', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            break;
        case 15:
            $sql = sprintf('ALTER TABLE `%s` CHANGE `media_location_id` `episode_asset_id` INT', \Podlove\Model\MediaFile::table_name());
            $wpdb->query($sql);
            break;
        case 16:
            $sql = sprintf('ALTER TABLE `%s` CHANGE `media_location_id` `episode_asset_id` INT', \Podlove\Model\Feed::table_name());
            $wpdb->query($sql);
            break;
        case 17:
            $sql = sprintf('ALTER TABLE `%s` RENAME TO `%s`', $wpdb->prefix . 'podlove_mediaformat', \Podlove\Model\FileType::table_name());
            $wpdb->query($sql);
            break;
        case 18:
            $sql = sprintf('ALTER TABLE `%s` CHANGE `media_format_id` `file_type_id` INT', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            break;
        case 19:
            \Podlove\Model\Template::build();
            break;
        case 20:
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `suffix` VARCHAR(255)', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            $sql = sprintf('ALTER TABLE `%s` DROP COLUMN `url_template`', \Podlove\Model\EpisodeAsset::table_name());
            $wpdb->query($sql);
            break;
        case 21:
            $podcast = Model\Podcast::get();
            $podcast->url_template = '%media_file_base_url%%episode_slug%%suffix%.%format_extension%';
            $podcast->save();
            break;
        case 22:
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `redirect_http_status` INT AFTER `redirect_url`', Model\Feed::table_name());
            $wpdb->query($sql);
            break;
        case 23:
            $sql = sprintf('ALTER TABLE `%s` DROP COLUMN `show_description`', Model\Feed::table_name());
            $wpdb->query($sql);
            break;
        case 24:
            $podcast = Model\Podcast::get();
            update_option('podlove_asset_assignment', array('image' => $podcast->supports_cover_art, 'chapters' => $podcast->chapter_file));
            break;
        case 25:
            // rename meta podlove_guid to _podlove_guid
            $episodes = Model\Episode::all();
            foreach ($episodes as $episode) {
                $post = get_post($episode->post_id);
                // skip revisions
                if ($post->post_status == 'inherit') {
                    continue;
                }
                $guid = get_post_meta($episode->post_id, 'podlove_guid', true);
                if (!$guid) {
                    $guid = $post->guid;
                }
                delete_post_meta($episode->post_id, 'podlove_guid');
                update_post_meta($episode->post_id, '_podlove_guid', $guid);
            }
            break;
        case 26:
            $wpdb->query(sprintf('ALTER TABLE `%s` MODIFY COLUMN `subtitle` TEXT', Model\Episode::table_name()));
            break;
        case 27:
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `record_date` DATETIME AFTER `chapters`', Model\Episode::table_name()));
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `publication_date` DATETIME AFTER `record_date`', Model\Episode::table_name()));
            break;
        case 28:
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `position` FLOAT AFTER `downloadable`', Model\EpisodeAsset::table_name()));
            $wpdb->query(sprintf('UPDATE `%s` SET position = id', Model\EpisodeAsset::table_name()));
            break;
        case 29:
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `embed_content_encoded` INT AFTER `limit_items`', Model\Feed::table_name()));
            break;
        case 30:
            $wpdb->query(sprintf('ALTER TABLE `%s` MODIFY `autoinsert` VARCHAR(255)', Model\Template::table_name()));
            break;
        case 32:
            flush_rewrite_rules();
            break;
        case 33:
            $apd = array('name' => 'Auphonic Production Description', 'type' => 'metadata', 'mime_type' => 'application/json', 'extension' => 'json');
            $f = new \Podlove\Model\FileType();
            foreach ($apd as $key => $value) {
                $f->{$key} = $value;
            }
            $f->save();
            break;
        case 34:
            $options = get_option('podlove', array());
            if (!array_key_exists('episode_archive', $options)) {
                $options['episode_archive'] = 'on';
            }
            if (!array_key_exists('episode_archive_slug', $options)) {
                $options['episode_archive_slug'] = '/podcast/';
            }
            if (!array_key_exists('use_post_permastruct', $options)) {
                $options['use_post_permastruct'] = 'off';
            }
            if (!array_key_exists('custom_episode_slug', $options)) {
                $options['custom_episode_slug'] = '/podcast/%podcast%/';
            } else {
                $options['custom_episode_slug'] = preg_replace('#/+#', '/', '/' . str_replace('#', '', $options['custom_episode_slug']));
            }
            update_option('podlove', $options);
            break;
        case 35:
            Model\Feed::build_indices();
            Model\FileType::build_indices();
            Model\EpisodeAsset::build_indices();
            Model\MediaFile::build_indices();
            Model\Episode::build_indices();
            Model\Template::build_indices();
            break;
        case 36:
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `etag` VARCHAR(255)', Model\MediaFile::table_name()));
            break;
        case 37:
            \Podlove\Modules\Base::activate('asset_validation');
            break;
        case 38:
            \Podlove\Modules\Base::activate('logging');
            break;
        case 39:
            // migrate previous template autoinsert settings
            $assignments = Model\TemplateAssignment::get_instance();
            $results = $wpdb->get_results(sprintf('SELECT * FROM `%s`', Model\Template::table_name()));
            foreach ($results as $template) {
                if ($template->autoinsert == 'beginning') {
                    $assignments->top = $template->id;
                } elseif ($template->autoinsert == 'end') {
                    $assignments->bottom = $template->id;
                }
            }
            $assignments->save();
            // remove template autoinsert column
            $sql = sprintf('ALTER TABLE `%s` DROP COLUMN `autoinsert`', \Podlove\Model\Template::table_name());
            $wpdb->query($sql);
            break;
        case 40:
            $wpdb->query(sprintf('UPDATE `%s` SET position = id WHERE position IS NULL', Model\EpisodeAsset::table_name()));
            break;
        case 41:
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `position` FLOAT AFTER `slug`', Model\Feed::table_name()));
            $wpdb->query(sprintf('UPDATE `%s` SET position = id', Model\Feed::table_name()));
            break;
        case 42:
            $wpdb->query('DELETE FROM `' . $wpdb->options . '` WHERE option_name LIKE "%podlove_chapters_string_%"');
            break;
        case 43:
            $podlove_options = get_option('podlove', array());
            $podlove_website = array('merge_episodes' => isset($podlove_options['merge_episodes']) ? $podlove_options['merge_episodes'] : false, 'hide_wp_feed_discovery' => isset($podlove_options['hide_wp_feed_discovery']) ? $podlove_options['hide_wp_feed_discovery'] : false, 'use_post_permastruct' => isset($podlove_options['use_post_permastruct']) ? $podlove_options['use_post_permastruct'] : false, 'custom_episode_slug' => isset($podlove_options['custom_episode_slug']) ? $podlove_options['custom_episode_slug'] : '/episode/%podcast%', 'episode_archive' => isset($podlove_options['episode_archive']) ? $podlove_options['episode_archive'] : false, 'episode_archive_slug' => isset($podlove_options['episode_archive_slug']) ? $podlove_options['episode_archive_slug'] : '/podcast/', 'url_template' => isset($podlove_options['url_template']) ? $podlove_options['url_template'] : '%media_file_base_url%%episode_slug%%suffix%.%format_extension%');
            $podlove_metadata = array('enable_episode_record_date' => isset($podlove_options['enable_episode_record_date']) ? $podlove_options['enable_episode_record_date'] : false, 'enable_episode_publication_date' => isset($podlove_options['enable_episode_publication_date']) ? $podlove_options['enable_episode_publication_date'] : false);
            $podlove_redirects = array('podlove_setting_redirect' => isset($podlove_options['podlove_setting_redirect']) ? $podlove_options['podlove_setting_redirect'] : array());
            add_option('podlove_website', $podlove_website);
            add_option('podlove_metadata', $podlove_metadata);
            add_option('podlove_redirects', $podlove_redirects);
            break;
        case 44:
            $wpdb->query('DELETE FROM `' . $wpdb->postmeta . '` WHERE meta_key = "last_validated_at"');
            break;
        case 45:
            delete_transient('podlove_auphonic_user');
            delete_transient('podlove_auphonic_presets');
            break;
        case 46:
            if (\Podlove\Modules\Base::is_active('contributors')) {
                // manually trigger activation if the old module was active
                $module = \Podlove\Modules\Contributors\Contributors::instance();
                $module->was_activated('contributors');
                // then, migrate existing contributors
                // register old taxonomy so it can be queried
                $args = array('hierarchical' => false, 'labels' => array(), 'show_ui' => true, 'show_tagcloud' => true, 'query_var' => true, 'rewrite' => array('slug' => 'contributor'));
                register_taxonomy('podlove-contributors', 'podcast', $args);
                $contributor_settings = get_option('podlove_contributors', array());
                $contributors = get_terms('podlove-contributors', array('hide_empty' => 0));
                if ($contributors && !is_wp_error($contributors) && \Podlove\Modules\Contributors\Model\Contributor::count() == 0) {
                    foreach ($contributors as $contributor) {
                        // create new contributor
                        $new = new \Podlove\Modules\Contributors\Model\Contributor();
                        $new->publicname = $contributor->name;
                        $new->realname = $contributor->name;
                        $new->slug = $contributor->slug;
                        $new->showpublic = true;
                        if (isset($contributor_settings[$contributor->term_id]['contributor_email'])) {
                            $email = $contributor_settings[$contributor->term_id]['contributor_email'];
                            if ($email) {
                                $new->privateemail = $email;
                                $new->avatar = $email;
                            }
                        }
                        $new->save();
                        // create contributions
                        $query = new \WP_Query(array('posts_per_page' => -1, 'post_type' => 'podcast', 'tax_query' => array(array('taxonomy' => 'podlove-contributors', 'field' => 'slug', 'terms' => $contributor->slug))));
                        while ($query->have_posts()) {
                            $post = $query->next_post();
                            $contribution = new \Podlove\Modules\Contributors\Model\EpisodeContribution();
                            $contribution->contributor_id = $new->id;
                            $contribution->episode_id = Model\Episode::find_one_by_post_id($post->ID)->id;
                            $contribution->save();
                        }
                    }
                }
            }
            break;
        case 47:
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `protected` TINYINT(1) NULL', \Podlove\Model\Feed::table_name()));
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `protection_type` TINYINT(1)', \Podlove\Model\Feed::table_name()));
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `protection_user` VARCHAR(60)', \Podlove\Model\Feed::table_name()));
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `protection_password` VARCHAR(64)', \Podlove\Model\Feed::table_name()));
            break;
        case 48:
            $podcast = Model\Podcast::get();
            $podcast->limit_items = '-1';
            $podcast->save();
            break;
        case 49:
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `explicit` TINYINT', Model\Episode::table_name()));
            break;
        case 50:
            $podcast = Model\Podcast::get();
            $podcast->license_type = 'other';
            $podcast->save();
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `license_type` VARCHAR(255) AFTER `publication_date`', Model\Episode::table_name()));
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `license_name` TEXT AFTER `license_type`', Model\Episode::table_name()));
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `license_url` TEXT AFTER `license_name`', Model\Episode::table_name()));
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `license_cc_allow_modifications` TEXT AFTER `license_url`', Model\Episode::table_name()));
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `license_cc_allow_commercial_use` TEXT AFTER `license_cc_allow_modifications`', Model\Episode::table_name()));
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `license_cc_license_jurisdiction` TEXT AFTER `license_cc_allow_commercial_use`', Model\Episode::table_name()));
            break;
        case 51:
            if (\Podlove\Modules\Base::is_active('contributors')) {
                \Podlove\Modules\Contributors\Model\ContributorGroup::build();
                $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `group_id` VARCHAR(255) AFTER `role_id`', \Podlove\Modules\Contributors\Model\EpisodeContribution::table_name()));
                $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `group_id` VARCHAR(255) AFTER `role_id`', \Podlove\Modules\Contributors\Model\ShowContribution::table_name()));
                $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `paypal` VARCHAR(255) AFTER `flattr`', \Podlove\Modules\Contributors\Model\Contributor::table_name()));
                $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `bitcoin` VARCHAR(255) AFTER `paypal`', \Podlove\Modules\Contributors\Model\Contributor::table_name()));
                $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `litecoin` VARCHAR(255) AFTER `bitcoin`', \Podlove\Modules\Contributors\Model\Contributor::table_name()));
                $wpdb->query(sprintf('ALTER TABLE `%s` DROP COLUMN `permanentcontributor`', \Podlove\Modules\Contributors\Model\Contributor::table_name()));
                $wpdb->query(sprintf('ALTER TABLE `%s` DROP COLUMN `role`', \Podlove\Modules\Contributors\Model\Contributor::table_name()));
            }
            break;
        case 52:
            if (\Podlove\Modules\Base::is_active('contributors')) {
                $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `jobtitle` VARCHAR(255) AFTER `department`', \Podlove\Modules\Contributors\Model\Contributor::table_name()));
            }
            break;
        case 53:
            // set all Episode as published (fix for ADN Module)
            $episodes = Model\Episode::all();
            foreach ($episodes as $episode) {
                $post = get_post($episode->post_id);
                if ($post->post_status == 'publish') {
                    update_post_meta($episode->post_id, '_podlove_episode_was_published', true);
                }
            }
            break;
        case 54:
            if (\Podlove\Modules\Base::is_active('contributors')) {
                $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `googleplus` TEXT AFTER `ADN`', \Podlove\Modules\Contributors\Model\Contributor::table_name()));
                $wpdb->query(sprintf('ALTER TABLE `%s` CHANGE COLUMN `showpublic` `visibility` TINYINT(1)', \Podlove\Modules\Contributors\Model\Contributor::table_name()));
            }
            break;
        case 55:
            if (\Podlove\Modules\Base::is_active('contributors')) {
                \Podlove\Modules\Contributors\Model\DefaultContribution::build();
                $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `comment` TEXT AFTER `position`', \Podlove\Modules\Contributors\Model\EpisodeContribution::table_name()));
                $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `comment` TEXT AFTER `position`', \Podlove\Modules\Contributors\Model\ShowContribution::table_name()));
            }
            break;
        case 56:
            // migrate Podcast Contributors to Default Contributors
            if (\Podlove\Modules\Base::is_active('contributors')) {
                $podcast_contributors = \Podlove\Modules\Contributors\Model\ShowContribution::all();
                foreach ($podcast_contributors as $podcast_contributor_key => $podcast_contributor) {
                    $new = new \Podlove\Modules\Contributors\Model\DefaultContribution();
                    $new->contributor_id = $podcast_contributor->contributor_id;
                    $new->group_id = $podcast_contributor->group_id;
                    $new->role_id = $podcast_contributor->role_id;
                    $new->position = $podcast_contributor->positon;
                    $new->save();
                }
            }
            break;
        case 57:
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `append_name_to_podcast_title` TINYINT(1) NULL AFTER `embed_content_encoded`', \Podlove\Model\Feed::table_name()));
            break;
        case 58:
            // if contributors module is active, activate social module
            if (\Podlove\Modules\Base::is_active('contributors')) {
                \Podlove\Modules\Base::activate('social');
            }
            break;
        case 59:
            if (\Podlove\Modules\Base::is_active('bitlove')) {
                $wpdb->query(sprintf("ALTER TABLE `%s` ADD COLUMN `bitlove` TINYINT(1) DEFAULT '0'", \Podlove\Model\Feed::table_name()));
            }
            break;
        case 60:
            \Podlove\Modules\Base::activate('oembed');
            \Podlove\Modules\Base::activate('feed_validation');
            break;
        case 61:
            $wpdb->query(sprintf('ALTER TABLE `%s` DROP COLUMN `publication_date`', Model\Episode::table_name()));
            break;
        case 62:
            // rename column
            $wpdb->query(sprintf('ALTER TABLE `%s` CHANGE COLUMN `record_date` `recording_date` DATETIME', Model\Episode::table_name()));
            // update settings
            $meta = get_option('podlove_metadata');
            if (isset($meta['enable_episode_publication_date'])) {
                unset($meta['enable_episode_publication_date']);
            }
            if (isset($meta['enable_episode_record_date'])) {
                $meta['enable_episode_recording_date'] = $meta['enable_episode_record_date'];
                unset($meta['enable_episode_record_date']);
            }
            update_option('podlove_metadata', $meta);
            break;
        case 63:
            if (\Podlove\Modules\Base::is_active('social')) {
                $tumblr_service = \Podlove\Modules\Social\Model\Service::find_one_by_property('title', 'Tumblr');
                $tumblr_service->url_scheme = 'http://%account-placeholder%.tumblr.com/';
                $tumblr_service->save();
            }
            break;
        case 64:
            if (\Podlove\Modules\Base::is_active('social')) {
                $services = array(array('title' => '500px', 'type' => 'social', 'description' => '500px Account', 'logo' => '500px-128.png', 'url_scheme' => 'https://500px.com/%account-placeholder%'), array('title' => 'Last.fm', 'type' => 'social', 'description' => 'Last.fm Account', 'logo' => 'lastfm-128.png', 'url_scheme' => 'https://www.lastfm.de/user/%account-placeholder%'), array('title' => 'OpenStreetMap', 'type' => 'social', 'description' => 'OpenStreetMap Account', 'logo' => 'openstreetmap-128.png', 'url_scheme' => 'https://www.openstreetmap.org/user/%account-placeholder%'), array('title' => 'Soup', 'type' => 'social', 'description' => 'Soup Account', 'logo' => 'soup-128.png', 'url_scheme' => 'http://%account-placeholder%.soup.io'));
                foreach ($services as $service_key => $service) {
                    $c = new \Podlove\Modules\Social\Model\Service();
                    $c->title = $service['title'];
                    $c->type = $service['type'];
                    $c->description = $service['description'];
                    $c->logo = $service['logo'];
                    $c->url_scheme = $service['url_scheme'];
                    $c->save();
                }
            }
            break;
        case 65:
            if (\Podlove\Modules\Base::is_active('social')) {
                $flattr_service = \Podlove\Modules\Social\Model\Service::find_one_by_where("`title` = 'Flattr' AND `type` = 'donation'");
                if ($flattr_service) {
                    $contributor_flattr_donations_accounts = \Podlove\Modules\Social\Model\ContributorService::find_all_by_property('service_id', $flattr_service->id);
                    foreach ($contributor_flattr_donations_accounts as $contributor_flattr_donations_account) {
                        $contributor = \Podlove\Modules\Contributors\Model\Contributor::find_by_id($contributor_flattr_donations_account->contributor_id);
                        if ($contributor && is_null($contributor->flattr)) {
                            $contributor->flattr = $contributor_flattr_donations_account->value;
                            $contributor->save();
                        }
                        $contributor_flattr_donations_account->delete();
                    }
                    $flattr_service->delete();
                }
            }
            break;
        case 66:
            // Temporary add license_type and CC license fields to episode model
            \Podlove\Model\Episode::property('license_type', 'VARCHAR(255)');
            \Podlove\Model\Episode::property('license_cc_allow_modifications', 'VARCHAR(255)');
            \Podlove\Model\Episode::property('license_cc_allow_commercial_use', 'VARCHAR(255)');
            \Podlove\Model\Episode::property('license_cc_license_jurisdiction', 'VARCHAR(255)');
            $podcast = \Podlove\Model\Podcast::get();
            $episodes = \Podlove\Model\Episode::all();
            // Migration for Podcast
            if ($podcast->license_type == 'cc' && $podcast->license_cc_allow_commercial_use !== '' && $podcast->license_cc_allow_modifications !== '' && $podcast->license_cc_license_jurisdiction !== '') {
                $license = array('version' => '3.0', 'commercial_use' => $podcast->license_cc_allow_commercial_use, 'modification' => $podcast->license_cc_allow_modifications, 'jurisdiction' => $podcast->license_cc_license_jurisdiction);
                $podcast->license_url = \Podlove\Model\License::get_url_from_license($license);
                $podcast->license_name = \Podlove\Model\License::get_name_from_license($license);
                $podcast->save();
            }
            // Migration for Episodes
            foreach ($episodes as $episode) {
                if ($episode->license_type == 'other' || $episode->license_cc_allow_commercial_use == '' || $episode->license_cc_allow_modifications == '' || $episode->license_cc_license_jurisdiction == '') {
                    continue;
                }
                $license = array('version' => '3.0', 'commercial_use' => $episode->license_cc_allow_commercial_use, 'modification' => $episode->license_cc_allow_modifications, 'jurisdiction' => $episode->license_cc_license_jurisdiction);
                $episode->license_url = \Podlove\Model\License::get_url_from_license($license);
                $episode->license_name = \Podlove\Model\License::get_name_from_license($license);
                $episode->save();
            }
            break;
        case 67:
            if (\Podlove\Modules\Base::is_active('social')) {
                $instagram_service = \Podlove\Modules\Social\Model\Service::find_one_by_where("`title` = 'Instagram' AND `type` = 'social'");
                if ($instagram_service) {
                    $instagram_service->url_scheme = 'https://instagram.com/%account-placeholder%';
                    $instagram_service->save();
                }
            }
            break;
        case 68:
            // Do that ADN module fix again, as we forgot to mark all episodes as published if the ADN module is activated
            $episodes = Model\Episode::all();
            foreach ($episodes as $episode) {
                $post = get_post($episode->post_id);
                if ($post->post_status == 'publish' && !get_post_meta($episode->post_id, '_podlove_episode_was_published', true)) {
                    update_post_meta($episode->post_id, '_podlove_episode_was_published', true);
                }
            }
            break;
        case 69:
            if (\Podlove\Modules\Base::is_active('app_dot_net')) {
                $adn = \Podlove\Modules\AppDotNet\App_Dot_Net::instance();
                if ($adn->get_module_option('adn_auth_key')) {
                    $adn->update_module_option('adn_automatic_announcement', 'on');
                }
            }
            break;
        case 70:
            \Podlove\Model\DownloadIntent::build();
            \Podlove\Model\UserAgent::build();
            break;
        case 71:
            // update for everyone, so even those with inactive service tables get updated
            $wpdb->query(sprintf('ALTER TABLE `%s` CHANGE COLUMN `type` `category` VARCHAR(255)', \Podlove\Modules\Social\Model\Service::table_name()));
            $wpdb->query(sprintf("ALTER TABLE `%s` ADD COLUMN `type` VARCHAR(255) AFTER `category`", \Podlove\Modules\Social\Model\Service::table_name()));
            $services = \Podlove\Modules\Social\Model\Service::all();
            foreach ($services as $service) {
                $service->type = strtolower($service->title);
                $service->save();
            }
            break;
        case 72:
            if (\Podlove\Modules\Base::is_active('social')) {
                $services = array(array('title' => 'Vimeo', 'type' => 'vimeo', 'category' => 'social', 'description' => 'Vimeo Account', 'logo' => 'vimeo-128.png', 'url_scheme' => 'http://vimeo.com/%account-placeholder%'), array('title' => 'about.me', 'type' => 'about.me', 'category' => 'social', 'description' => 'about.me Account', 'logo' => 'aboutme-128.png', 'url_scheme' => 'http://about.me/%account-placeholder%'), array('title' => 'Gittip', 'type' => 'gittip', 'category' => 'donation', 'description' => 'Gittip Account', 'logo' => 'gittip-128.png', 'url_scheme' => 'https://www.gittip.com/%account-placeholder%'));
                foreach ($services as $service_key => $service) {
                    $c = new \Podlove\Modules\Social\Model\Service();
                    $c->title = $service['title'];
                    $c->type = $service['type'];
                    $c->category = $service['category'];
                    $c->description = $service['description'];
                    $c->logo = $service['logo'];
                    $c->url_scheme = $service['url_scheme'];
                    $c->save();
                }
            }
            break;
        case 73:
            if (\Podlove\Modules\Base::is_active('social')) {
                $jabber_service = \Podlove\Modules\Social\Model\Service::find_one_by_where("`type` = 'jabber' AND `category` = 'social'");
                if ($jabber_service) {
                    $jabber_service->url_scheme = 'jabber:%account-placeholder%';
                    $jabber_service->save();
                }
            }
            break;
        case 74:
            Model\GeoArea::build();
            Model\GeoAreaName::build();
            \Podlove\Geo_Ip::register_updater_cron();
            break;
        case 75:
            $tracking = get_option('podlove_tracking');
            $tracking['mode'] = 0;
            update_option('podlove_tracking', $tracking);
            break;
        case 76:
            set_transient('podlove_needs_to_flush_rewrite_rules', true);
            break;
        case 77:
            // delete empty user agents
            $userAgentTable = Model\UserAgent::table_name();
            $downloadIntentTable = Model\DownloadIntent::table_name();
            $sql = "SELECT\n\t\t\t\tdi.id\n\t\t\tFROM\n\t\t\t\t{$downloadIntentTable} di\n\t\t\t\tJOIN {$userAgentTable} ua ON ua.id = di.user_agent_id\n\t\t\tWHERE\n\t\t\t\tua.user_agent IS NULL";
            $ids = $wpdb->get_col($sql);
            if (is_array($ids) && count($ids)) {
                $sql = "UPDATE {$downloadIntentTable} SET user_agent_id = NULL WHERE id IN (" . implode(",", $ids) . ")";
                $wpdb->query($sql);
                $sql = "DELETE FROM {$userAgentTable} WHERE user_agent IS NULL";
                $wpdb->query($sql);
            }
            break;
        case 78:
            if (\Podlove\Modules\Base::is_active('social')) {
                $c = new \Podlove\Modules\Social\Model\Service();
                $c->title = 'Auphonic Credits';
                $c->category = 'donation';
                $c->type = 'auphonic credits';
                $c->description = 'Auphonic Account';
                $c->logo = 'auphonic-128.png';
                $c->url_scheme = 'https://auphonic.com/donate_credits?user=%account-placeholder%';
                $c->save();
            }
            break;
        case 79:
            set_transient('podlove_needs_to_flush_rewrite_rules', true);
            $cache = \Podlove\Cache\TemplateCache::get_instance();
            $cache->setup_purge();
            break;
        case 80:
            $sql = sprintf('ALTER TABLE `%s` ADD COLUMN `httprange` VARCHAR(255)', \Podlove\Model\DownloadIntent::table_name());
            $wpdb->query($sql);
            break;
        case 81:
            // remove all caches with old namespace
            $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE \"_transient_podlove_cache%\"");
            break;
        case 82:
            // set all redirect entries to active
            $redirect_settings = \Podlove\get_setting('redirects', 'podlove_setting_redirect');
            foreach ($redirect_settings as $index => $data) {
                $redirect_settings[$index]['active'] = 'active';
            }
            update_option('podlove_redirects', array('podlove_setting_redirect' => $redirect_settings));
            break;
        case 83:
            \Podlove\Model\DownloadIntentClean::build();
            $alterations = array('ALTER TABLE `%s` ADD COLUMN `bot` TINYINT', 'ALTER TABLE `%s` ADD COLUMN `client_name` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `client_version` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `client_type` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `os_name` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `os_version` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `device_brand` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `device_model` VARCHAR(255)');
            foreach ($alterations as $sql) {
                $wpdb->query(sprintf($sql, Model\UserAgent::table_name()));
            }
            Model\UserAgent::reparse_all();
            break;
        case 84:
            delete_option('podlove_tpl_cache_keys');
            break;
        case 85:
            add_option('podlove_tracking_delete_head_requests', 1);
            break;
        case 86:
            if (\Podlove\Modules\Base::is_active('social')) {
                $c = new \Podlove\Modules\Social\Model\Service();
                $c->title = 'Foursquare';
                $c->category = 'social';
                $c->type = 'foursquare';
                $c->description = 'Foursquare Account';
                $c->logo = 'foursquare-128.png';
                $c->url_scheme = 'https://foursquare.com/%account-placeholder%';
                $c->save();
                $services = array(array('title' => 'ResearchGate', 'name' => 'researchgate', 'category' => 'social', 'description' => 'ResearchGate URL', 'logo' => 'researchgate-128.png', 'url_scheme' => '%account-placeholder%'), array('title' => 'ORCiD', 'name' => 'orcid', 'category' => 'social', 'description' => 'ORCiD', 'logo' => 'orcid-128.png', 'url_scheme' => 'https://orcid.org/%account-placeholder%'), array('title' => 'Scopus', 'name' => 'scous', 'category' => 'social', 'description' => 'Scopus Author ID', 'logo' => 'scopus-128.png', 'url_scheme' => 'https://www.scopus.com/authid/detail.url?authorId=%account-placeholder%'));
                foreach ($services as $service_key => $service) {
                    $c = new \Podlove\Modules\Social\Model\Service();
                    $c->title = $service['title'];
                    $c->category = $service['category'];
                    $c->type = $service['name'];
                    $c->description = $service['description'];
                    $c->logo = $service['logo'];
                    $c->url_scheme = $service['url_scheme'];
                    $c->save();
                }
            }
            break;
        case 87:
            if (\Podlove\Modules\Base::is_active('app_dot_net')) {
                $adn = \Podlove\Modules\AppDotNet\App_Dot_Net::instance();
                if ($adn->get_module_option('adn_auth_key')) {
                    $adn->update_module_option('adn_poster_image_fallback', 'on');
                }
            }
            break;
        case 88:
            $service = new \Podlove\Modules\Social\Model\Service();
            $service->title = 'Email';
            $service->category = 'social';
            $service->type = 'email';
            $service->description = 'Email';
            $service->logo = 'email-128.png';
            $service->url_scheme = 'mailto:%account-placeholder%';
            $service->save();
            break;
        case 89:
            $email_service = \Podlove\Modules\Social\Model\Service::find_one_by_type('email');
            foreach (\Podlove\Modules\Contributors\Model\Contributor::all() as $contributor) {
                if (!$contributor->publicemail) {
                    continue;
                }
                $contributor_service = new \Podlove\Modules\Social\Model\ContributorService();
                $contributor_service->contributor_id = $contributor->id;
                $contributor_service->service_id = $email_service->id;
                $contributor_service->value = $contributor->publicemail;
                $contributor_service->save();
            }
            break;
        case 90:
            \Podlove\Modules\Base::activate('subscribe_button');
            break;
        case 91:
            $c = new \Podlove\Modules\Social\Model\Service();
            $c->title = 'Miiverse';
            $c->category = 'social';
            $c->type = 'miiverse';
            $c->description = 'Miiverse Account';
            $c->logo = 'miiverse-128.png';
            $c->url_scheme = 'https://miiverse.nintendo.net/users/%account-placeholder%';
            $c->save();
            break;
        case 92:
            $c = new \Podlove\Modules\Social\Model\Service();
            $c->title = 'Prezi';
            $c->category = 'social';
            $c->type = 'prezi';
            $c->description = 'Prezis';
            $c->logo = 'prezi-128.png';
            $c->url_scheme = 'http://prezi.com/user/%account-placeholder%';
            $c->save();
            break;
        case 93:
            // podlove_init_user_agent_refresh();
            // do nothing instead, because see 94 below
            break;
        case 94:
            // this is a duplicate of migration 83 but it looks like that didn't work.
            Model\DownloadIntentClean::build();
            $alterations = array('ALTER TABLE `%s` ADD COLUMN `bot` TINYINT', 'ALTER TABLE `%s` ADD COLUMN `client_name` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `client_version` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `client_type` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `os_name` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `os_version` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `device_brand` VARCHAR(255)', 'ALTER TABLE `%s` ADD COLUMN `device_model` VARCHAR(255)');
            foreach ($alterations as $sql) {
                $wpdb->query(sprintf($sql, Model\UserAgent::table_name()));
            }
            podlove_init_user_agent_refresh();
            // manually trigger intent cron after user agents are parsed
            // parameter to make sure WP does not skip it due to 10 minute rule
            wp_schedule_single_event(time() + 120, 'podlove_cleanup_download_intents', ['really' => true]);
            // manually trigger average cron after intents are calculated
            wp_schedule_single_event(time() + 240, 'recalculate_episode_download_average', ['really' => true]);
            break;
        case 95:
            // add missing flattr column
            $wpdb->query(sprintf('ALTER TABLE `%s` ADD COLUMN `flattr` VARCHAR(255) AFTER `avatar`', \Podlove\Modules\Contributors\Model\Contributor::table_name()));
            break;
        case 96:
            \Podlove\DeleteHeadRequests::init();
            break;
        case 97:
            // recalculate all downloads average data
            $wpdb->query(sprintf('DELETE FROM `%s` WHERE `meta_key` LIKE "_podlove_eda%%"', $wpdb->postmeta));
            break;
        case 98:
            delete_transient('podlove_dashboard_stats_contributors');
            break;
        case 99:
            // Activate network module for migrating users.
            // Core modules are automatically activated for _new_ setups and
            // whenever modules change. Since this can't be guaranteed for
            // existing setups, it must be triggered manually.
            \Podlove\Modules\Networks\Networks::instance()->was_activated();
            break;
        case 101:
            // add patreon
            if (\Podlove\Modules\Social\Model\Service::table_exists()) {
                \Podlove\Modules\Social\RepairSocial::fix_missing_services();
            }
            break;
        case 102:
            // update logos
            if (\Podlove\Modules\Social\Model\Service::table_exists()) {
                \Podlove\Modules\Social\Social::update_existing_services();
            }
            break;
        case 103:
            $assignment = get_option('podlove_template_assignment', []);
            if ($assignment['top'] && is_numeric($assignment['top'])) {
                $assignment['top'] = Model\Template::find_by_id($assignment['top'])->title;
            }
            if ($assignment['bottom'] && is_numeric($assignment['bottom'])) {
                $assignment['bottom'] = Model\Template::find_by_id($assignment['bottom'])->title;
            }
            update_option('podlove_template_assignment', $assignment);
            break;
        case 104:
            \Podlove\unschedule_events(\Podlove\Cache\TemplateCache::CRON_PURGE_HOOK);
            break;
        case 105:
            // activate flattr plugin
            \Podlove\Modules\Base::activate('flattr');
            // migrate flattr data
            $podcast = Model\Podcast::get();
            $settings = get_option('podlove_flattr', []);
            $settings['account'] = $podcast->flattr;
            $settings['contributor_shortcode_default'] = 'yes';
            update_option('podlove_flattr', $settings);
            break;
        case 106:
            podlove_init_user_agent_refresh();
            break;
        case 107:
            // skipped
            break;
        case 108:
            podlove_init_user_agent_refresh();
            break;
        case 109:
            \podlove_init_capabilities();
            break;
        case 110:
            if (\Podlove\Modules\Social\Model\Service::table_exists()) {
                \Podlove\Modules\Social\Social::update_existing_services();
                \Podlove\Modules\Social\Social::build_missing_services();
            }
            break;
        case 111:
            if (\Podlove\Modules\Social\Model\Service::table_exists()) {
                \Podlove\Modules\Social\Social::update_existing_services();
                \Podlove\Modules\Social\Social::build_missing_services();
            }
            break;
    }
}
 private function get_chapters_object()
 {
     if (!$this->chapters_raw) {
         $this->chapters_raw = $this->get_raw_chapters_string();
     }
     if (!$this->chapters_raw) {
         return NULL;
     }
     $asset_assignment = Model\AssetAssignment::get_instance();
     if ($asset_assignment->chapters == 'manual') {
         return Parser\Mp4chaps::parse($this->chapters_raw);
     }
     if (!($chapters_asset = Model\EpisodeAsset::find_one_by_id($asset_assignment->chapters))) {
         return NULL;
     }
     $mime_type = $chapters_asset->file_type()->mime_type;
     $chapters = false;
     switch ($mime_type) {
         case 'application/xml':
             $chapters = Parser\PSC::parse($this->chapters_raw);
             break;
         case 'application/json':
             $chapters = Parser\JSON::parse($this->chapters_raw);
             break;
         case 'text/plain':
             switch ($this->chapters_raw[0]) {
                 case '[':
                 case '{':
                     $chapters = Parser\JSON::parse($this->chapters_raw);
                     break;
                 case '<':
                     $chapters = Parser\PSC::parse($this->chapters_raw);
                     break;
                 default:
                     $chapters = Parser\Mp4chaps::parse($this->chapters_raw);
                     break;
             }
             break;
     }
     return $chapters;
 }
function migrate_post($post_id)
{
    $post = get_post($post_id);
    $migration_settings = get_option('podlove_migration', array());
    $post_content = $post->post_content;
    if ($migration_settings['cleanup']['player']) {
        $post_content = preg_replace('/\\[(powerpress|podloveaudio|podlovevideo|display_podcast)[^\\]]*\\]/', '', $post_content);
    }
    $new_post = array('menu_order' => $post->menu_order, 'comment_status' => $post->comment_status, 'ping_status' => $post->ping_status, 'post_author' => $post->post_author, 'post_content' => $post_content, 'post_excerpt' => $post->post_excerpt, 'post_mime_type' => $post->post_mime_type, 'post_parent' => $post_id, 'post_password' => $post->post_password, 'post_status' => 'pending', 'post_title' => $post->post_title, 'post_type' => 'podcast', 'post_date' => $post->post_date, 'post_date_gmt' => get_gmt_from_date($post->post_date));
    $new_slug = NULL;
    switch ($migration_settings['post_slug']) {
        case 'wordpress':
            $new_slug = $post->post_name;
            break;
        case 'file':
            $new_slug = Assistant::get_file_slug($post);
            break;
        case 'number':
            $new_slug = Assistant::get_number_slug($post);
            break;
    }
    $override_slug = function ($data, $postarr) use($new_slug) {
        if ($new_slug) {
            $data['post_name'] = $new_slug;
        }
        return $data;
    };
    add_filter('wp_insert_post_data', $override_slug, 10, 2);
    $new_post_id = wp_insert_post($new_post);
    remove_filter('wp_insert_post_data', $override_slug, 10, 2);
    $new_post = get_post($new_post_id);
    // update guid
    update_post_meta($new_post_id, '_podlove_guid', $post->guid);
    // add redirect from previous url
    add_post_meta($new_post_id, 'podlove_alternate_url', get_permalink($post_id));
    // prevent adn module from triggering a post
    update_post_meta($new_post_id, '_podlove_episode_was_published', true);
    // migrate taxonomies
    $taxonomies = get_object_taxonomies(get_post_type($post_id));
    foreach ($taxonomies as $tax) {
        $terms = wp_get_object_terms($post_id, $tax);
        $term = array();
        foreach ($terms as $t) {
            $term[] = $t->slug;
        }
        wp_set_object_terms($new_post_id, $term, $tax);
    }
    $post_data = new Legacy_Post_Parser($post_id);
    $episode = Model\Episode::find_or_create_by_post_id($new_post_id);
    $episode->slug = Assistant::get_episode_slug($post, $migration_settings['slug']);
    $episode->duration = $post_data->get_duration();
    $episode->subtitle = $post_data->get_subtitle();
    $episode->summary = $post_data->get_summary();
    $episode->save();
    foreach (Model\EpisodeAsset::all() as $asset) {
        Model\MediaFile::find_or_create_by_episode_id_and_episode_asset_id($episode->id, $asset->id);
    }
    // copy all meta
    $meta = get_post_meta($post_id);
    foreach ($meta as $key => $values) {
        if (!in_array($key, array('enclosure', '_podPressPostSpecific', '_podPressMedia')) || !$migration_settings['cleanup']['enclosures']) {
            foreach ($values as $value) {
                add_post_meta($new_post_id, $key, $value);
            }
        }
    }
    // copy all comments
    $comments_map = array();
    // map old comment IDs to new comment IDs
    foreach (get_comments(array('post_id' => $post_id, 'order' => 'ASC')) as $comment) {
        $old_comment_id = $comment->comment_ID;
        $comment->comment_post_ID = $new_post_id;
        if ($comment->comment_parent && isset($comments_map[$comment->comment_parent])) {
            $comment->comment_parent = $comments_map[$comment->comment_parent];
        }
        $new_comment_id = wp_insert_comment((array) $comment);
        $comments_map[$old_comment_id] = $new_comment_id;
    }
    return $new_post_id;
}
    public static function chart()
    {
        $episode = Model\Episode::find_one_by_id((int) $_REQUEST['episode']);
        $post = get_post($episode->post_id);
        ?>
		<div id="chart-zoom-selection" class="chart-menubar">
			<span>Zoom</span>
			<a href="#" data-hours="24" class="button button-secondary">1d</a>
			<a href="#" data-hours="168" class="button button-secondary">1w</a>
			<a href="#" data-hours="672" class="button button-secondary">4w</a>
			<a href="#" data-hours="0" class="button button-secondary">all</a>
		</div>

		<div id="chart-grouping-selection" class="chart-menubar">
			<span>Unit</span>
			<a href="#" data-hours="1" class="button button-secondary">1h</a>
			<a href="#" data-hours="2" class="button button-secondary">2h</a>
			<!-- <a href="#" data-hours="3" class="button button-secondary">3h</a> -->
			<a href="#" data-hours="4" class="button button-secondary">4h</a>
			<a href="#" data-hours="6" class="button button-secondary">6h</a>
			<a href="#" data-hours="12" class="button button-secondary">12h</a>
			<a href="#" data-hours="24" class="button button-secondary">1d</a>
			<a href="#" data-hours="168" class="button button-secondary">1w</a>
			<a href="#" data-hours="672" class="button button-secondary">4w</a>
		</div>

		<div id="episode-performance-chart" data-episode="<?php 
        echo $episode->id;
        ?>
">
		</div>

		<div id="episode-range-chart"></div>

		<section id="episode-source-chart-wrapper" class="chart-wrapper" data-tile-id="download_source">
			<div id="episode-source-chart">
				<h1>Download Source <a href="#" class="reset" style="display: none"><small>reset</small></a></h1>
			</div>
		</section>

		<section id="episode-context-chart-wrapper" class="chart-wrapper" data-tile-id="download_context">
			<div id="episode-context-chart">
				<h1>Download Context <a href="#" class="reset" style="display: none"><small>reset</small></a></h1>
			</div>
		</section>

		<section id="episode-asset-chart-wrapper" class="chart-wrapper" data-tile-id="asset">
			<div id="episode-asset-chart">
				<h1>Episode Asset <a href="#" class="reset" style="display: none"><small>reset</small></a></h1>
			</div>
		</section>

		<section id="episode-client-chart-wrapper" class="chart-wrapper" data-tile-id="podcast_client">
			<div id="episode-client-chart">
				<h1>Podcast Client <a href="#" class="reset" style="display: none"><small>reset</small></a></h1>
			</div>
		</section>

		<section id="episode-system-chart-wrapper" class="chart-wrapper" data-tile-id="operating_system">
			<div id="episode-system-chart">
				<h1>Operating System <a href="#" class="reset" style="display: none"><small>reset</small></a></h1>
			</div>
		</section>

		<section id="episode-weekday-chart-wrapper" class="chart-wrapper" data-tile-id="day_of_week">
			<div id="episode-weekday-chart">
				<h1>Day of Week <a href="#" class="reset" style="display: none"><small>reset</small></a></h1>
			</div>
		</section>

		<div style="clear: both"></div>

		<script type="text/javascript">
		var assetNames = <?php 
        $assets = Model\EpisodeAsset::all();
        echo json_encode(array_combine(array_map(function ($a) {
            return $a->id;
        }, $assets), array_map(function ($a) {
            return $a->title;
        }, $assets)));
        ?>
;
		</script>

		<style type="text/css">
		section.chart-wrapper {
			float: left;
			height: 320px;
		}

		section.chart-wrapper h1 {
			font-size: 14px;
			margin-left: 10px;
		}

		section.chart-wrapper div {
			width: 285px;
			height: 285px;
		}

		.chart-wrapper h1, 
		.chart-wrapper h1 small {
			line-height: 19px;
			height: 19px;
		}

		.chart-wrapper h1 a {
			text-decoration: none;
		}

		.chart-menubar:first-child { float: right; }
		.chart-menubar:last-child  { float: left; }

		.chart-menubar span { line-height: 26px; }

		#episode-performance-chart {
			float: none;
			height: 250px
		}

		#episode-range-chart {
			float: none;
			height: 80px;
			margin-top: -15px;
		}

		#episode-source-chart g.row text,
		#episode-context-chart g.row text,
		#episode-weekday-chart g.row text,
		#episode-client-chart g.row text,
		#episode-system-chart g.row text,
		#episode-asset-chart g.row text {
			fill: black;
		}
		</style>

		<?php 
    }
Пример #23
0
    public function form_fields()
    {
        $formats = array('audio' => array('mp3' => array('title' => __('MP3 Audio', 'podlove'), 'mime_type' => 'audio/mpeg'), 'mp4' => array('title' => __('MP4 Audio', 'podlove'), 'mime_type' => 'audio/mp4'), 'ogg' => array('title' => __('OGG Audio', 'podlove'), 'mime_type' => 'audio/ogg')), 'video' => array('mp4' => array('title' => __('MP4 Video', 'podlove'), 'mime_type' => 'video/mp4'), 'ogg' => array('title' => __('OGG Video', 'podlove'), 'mime_type' => 'video/ogg'), 'webm' => array('title' => __('Webm Video', 'podlove'), 'mime_type' => 'video/webm')));
        $formats_data = get_option('podlove_webplayer_formats', array());
        $episode_assets = Model\EpisodeAsset::all();
        foreach ($formats as $format => $extensions) {
            foreach ($extensions as $extension => $extension_data) {
                $label = $extension_data['title'];
                $mime_type = $extension_data['mime_type'];
                $id = sprintf('podlove_webplayer_formats_%s_%s', $format, $extension);
                $name = sprintf('podlove_webplayer_formats[%s][%s]', $format, $extension);
                $value = isset($formats_data[$format]) && isset($formats_data[$format][$extension]) ? $formats_data[$format][$extension] : 0;
                ?>
				<tr valign="top">
					<th scope="row" valign="top">
						<label for="<?php 
                echo $id;
                ?>
"><?php 
                echo $label;
                ?>
</label>
					</th>
					<td>
						<div>
							<select name="<?php 
                echo $name;
                ?>
" id="<?php 
                echo $id;
                ?>
">
								<option value="0" <?php 
                selected(0, $value);
                ?>
 ><?php 
                echo __('Unused', 'podlove');
                ?>
</option>
								<?php 
                foreach ($episode_assets as $episode_asset) {
                    ?>
									<?php 
                    $file_type = $episode_asset->file_type();
                    ?>
									<?php 
                    if ($file_type && $file_type->mime_type === $mime_type) {
                        ?>
										<option value="<?php 
                        echo $episode_asset->id;
                        ?>
" <?php 
                        selected($episode_asset->id, $value);
                        ?>
><?php 
                        echo $episode_asset->title;
                        ?>
</option>
									<?php 
                    }
                    ?>
								<?php 
                }
                ?>
							</select>
						</div>
					</td>
				</tr>
				<?php 
            }
        }
    }
Пример #24
0
function create_episode()
{
    $slug = isset($_REQUEST['slug']) ? $_REQUEST['slug'] : NULL;
    $title = isset($_REQUEST['title']) ? $_REQUEST['title'] : NULL;
    if (!$slug || !$title) {
        die;
    }
    $args = array('post_type' => 'podcast', 'post_title' => $title, 'post_content' => \Podlove\Podcast_Post_Type::$default_post_content);
    // create post
    $post_id = wp_insert_post($args);
    // link episode and release
    $episode = \Podlove\Model\Episode::find_or_create_by_post_id($post_id);
    $episode->slug = $slug;
    $episode->enable = true;
    $episode->active = true;
    $episode->save();
    // activate all media files
    $episode_assets = Model\EpisodeAsset::all();
    foreach ($episode_assets as $episode_asset) {
        $media_file = new \Podlove\Model\MediaFile();
        $media_file->episode_id = $episode->id;
        $media_file->episode_asset_id = $episode_asset->id;
        $media_file->save();
    }
    // generate response
    $result = array();
    $result['post_id'] = $post_id;
    $result['post_edit_url'] = get_edit_post_link($post_id);
    header('Cache-Control: no-cache, must-revalidate');
    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
    header('Content-type: application/json');
    echo json_encode($result);
    die;
}
Пример #25
0
    public function form_fields()
    {
        $formats_data = get_option('podlove_webplayer_formats', array());
        $episode_assets = Model\EpisodeAsset::all();
        foreach (self::formats() as $format => $extensions) {
            ?>
			<tr valign="top">
				<th scope="row" valign="top" colspan="2">
					<h3><?php 
            echo ucfirst($format);
            ?>
</h3>
				</th>
			</tr>
			<?php 
            foreach ($extensions as $extension => $extension_data) {
                $label = $extension_data['title'];
                $mime_types = $extension_data['mime_types'];
                $id = sprintf('podlove_webplayer_formats_%s_%s', $format, $extension);
                $name = sprintf('podlove_webplayer_formats[%s][%s]', $format, $extension);
                $value = isset($formats_data[$format]) && isset($formats_data[$format][$extension]) ? $formats_data[$format][$extension] : 0;
                ?>
				<tr valign="top">
					<th scope="row" valign="top">
						<label for="<?php 
                echo $id;
                ?>
"><?php 
                echo $label;
                ?>
</label>
					</th>
					<td>
						<div>
							<select name="<?php 
                echo $name;
                ?>
" id="<?php 
                echo $id;
                ?>
">
								<option value="0" <?php 
                selected(0, $value);
                ?>
 ><?php 
                echo __('Unused', 'podlove');
                ?>
</option>
								<?php 
                foreach ($episode_assets as $episode_asset) {
                    ?>
									<?php 
                    $file_type = $episode_asset->file_type();
                    ?>
									<?php 
                    if ($file_type && in_array($file_type->mime_type, $mime_types)) {
                        ?>
										<option value="<?php 
                        echo $episode_asset->id;
                        ?>
" <?php 
                        selected($episode_asset->id, $value);
                        ?>
><?php 
                        echo $episode_asset->title;
                        ?>
</option>
									<?php 
                    }
                    ?>
								<?php 
                }
                ?>
							</select>
						</div>
					</td>
				</tr>
				<?php 
            }
        }
        // advanced settings
        $settings = array('inject' => array('label' => __('Insert player automatically', 'podlove'), 'description' => __('Automatically insert web player shortcode at beginning or end of an episode. Alternatvely, use the shortcode <code>[podlove-episode-web-player]</code>.', 'podlove'), 'options' => array('manually' => __('insert manually via shortcode', 'podlove'), 'beginning' => __('insert at the beginning', 'podlove'), 'end' => __('insert at the end', 'podlove'))), 'chaptersVisible' => array('label' => __('Chapters Visibility', 'podlove'), 'options' => array('true' => __('Visible when player loads', 'podlove'), 'false' => __('Hidden when player loads', 'podlove'))), 'version' => array('label' => __('Player Version', 'podlove'), 'options' => array('player_v2' => __('Podlove Web Player 2', 'podlove'), 'player_v3' => __('Podlove Web Player 3 (unstable beta, don\'t use in production)', 'podlove'))));
        ?>
		<tr valign="top">
			<th scope="row" valign="top" colspan="2">
				<h3><?php 
        echo __('Settings', 'podlove');
        ?>
</h3>
			</th>
		</tr>
		<?php 
        foreach ($settings as $setting_key => $field_values) {
            ?>
			<tr class="row_<?php 
            echo $setting_key;
            ?>
">
				<th scope="row" valign="top">
					<?php 
            if (isset($field_values['label']) && $field_values['label']) {
                ?>
						<label for="<?php 
                echo $setting_key;
                ?>
"><?php 
                echo $field_values['label'];
                ?>
</label>
					<?php 
            }
            ?>
				</th>
				<td>
					<select name="podlove_webplayer_settings[<?php 
            echo $setting_key;
            ?>
]" id="<?php 
            echo $setting_key;
            ?>
">
						<?php 
            foreach ($field_values['options'] as $key => $value) {
                ?>
							<option value="<?php 
                echo esc_attr($key);
                ?>
" <?php 
                if ($key == \Podlove\get_webplayer_setting($setting_key)) {
                    ?>
 selected="selected"<?php 
                }
                ?>
><?php 
                echo $value;
                ?>
</option>
						<?php 
            }
            ?>
					</select>
					<?php 
            if (isset($field_values['description']) && $field_values['description']) {
                ?>
						<div class="description"><?php 
                echo $field_values['description'];
                ?>
</div>
					<?php 
            }
            ?>
				</td>
			</tr>
		<?php 
        }
        ?>
		<?php 
    }
 /**
  * Get playable files for player, based on episode and player assignments.
  * 
  * @param  array  $formats      array of formats like mp3, mp3, ogg, opus, webm
  * @param  string $media_type   audio or video
  * @return array of \Podlove\Model\MediaFile
  */
 private function get_playable_files($formats, $media_type)
 {
     $playable_files = [];
     $player_format_assignments = get_option('podlove_webplayer_formats');
     if (empty($player_format_assignments)) {
         error_log(print_r("Podlove Web Player: No assets are assigned.", true));
         return [];
     }
     foreach ($formats as $format) {
         if (!isset($player_format_assignments[$media_type][$format])) {
             continue;
         }
         $episode_asset = EpisodeAsset::find_by_id($player_format_assignments[$media_type][$format]);
         if (!$episode_asset) {
             continue;
         }
         $media_file = MediaFile::find_by_episode_id_and_episode_asset_id($this->episode->id, $episode_asset->id);
         if ($media_file && $media_file->is_valid()) {
             $playable_files[] = $media_file;
         }
     }
     return $playable_files;
 }
Пример #27
0
/**
 * Provides shortcode to display web player.
 *
 * Right now there is only audio support.
 *
 * Usage:
 * 	[podlove-web-player]
 * 	
 * @param  array $options
 * @return string
 */
function webplayer_shortcode($options)
{
    global $post;
    $episode = Model\Episode::find_or_create_by_post_id($post->ID);
    $podcast = Model\Podcast::get_instance();
    $formats_data = get_option('podlove_webplayer_formats');
    if (!count($formats_data)) {
        return;
    }
    $available_formats = array();
    $audio_formats = array('mp3', 'mp4', 'ogg');
    foreach ($audio_formats as $audio_format) {
        $episode_asset = Model\EpisodeAsset::find_by_id($formats_data['audio'][$audio_format]);
        if (!$episode_asset) {
            continue;
        }
        $media_file = Model\MediaFile::find_by_episode_id_and_episode_asset_id($episode->id, $episode_asset->id);
        if ($media_file) {
            $available_formats[] = sprintf('%s="%s"', $audio_format, $media_file->get_file_url());
        }
    }
    $chapters = '';
    if ($episode->chapters) {
        $chapters = 'chapters="_podlove_chapters"';
    }
    return do_shortcode('[podloveaudio ' . implode(' ', $available_formats) . ' ' . $chapters . ']');
}
Пример #28
0
 private function form_template($feed, $action, $button_text = NULL)
 {
     $form_args = array('context' => 'podlove_feed', 'hidden' => array('feed' => $feed->id, 'action' => $action), 'submit_button' => false, 'form_end' => function () {
         echo "<p>";
         submit_button(__('Save Changes'), 'primary', 'submit', false);
         echo " ";
         submit_button(__('Save Changes and Continue Editing', 'podlove'), 'secondary', 'submit_and_stay', false);
         echo "</p>";
     });
     \Podlove\Form\build_for($feed, $form_args, function ($form) {
         $wrapper = new \Podlove\Form\Input\TableWrapper($form);
         $feed = $form->object;
         $podcast = \Podlove\Model\Podcast::get();
         $episode_assets = \Podlove\Model\EpisodeAsset::all();
         $assets = array();
         foreach ($episode_assets as $asset) {
             $assets[$asset->id] = $asset->title;
         }
         $wrapper->subheader(__('Basic Settings', 'podlove'));
         $wrapper->select('episode_asset_id', array('label' => __('Episode Media File', 'podlove') . \Podlove\get_help_link('podlove_help_feed_asset'), 'options' => $assets, 'html' => array('class' => 'required')));
         $wrapper->string('name', array('label' => __('Feed Name', 'podlove'), 'description' => __('Some podcast clients may display this title to describe the feed content.', 'podlove'), 'html' => array('class' => 'regular-text required podlove-check-input')));
         $wrapper->checkbox('append_name_to_podcast_title', array('label' => __('Append Feed Name to Podcast title', 'podlove'), 'description' => sprintf(__('Structure of the feed title. Preview: %s', 'podlove'), $podcast->title . '<span id="feed_title_preview_append"></span>'), 'default' => false));
         $wrapper->string('slug', array('label' => __('Slug', 'podlove') . \Podlove\get_help_link('podlove_help_feed_slug'), 'description' => $feed ? sprintf(__('Feed identifier. URL Preview: %s', 'podlove'), '<span id="feed_subscribe_url_preview">' . $feed->get_subscribe_url() . '</span>') : '', 'html' => array('class' => 'regular-text required podlove-check-input')));
         $wrapper->checkbox('discoverable', array('label' => __('Discoverable?', 'podlove'), 'description' => __('Embed a meta tag into the head of your site so browsers and feed readers will find the link to the feed.', 'podlove'), 'default' => true));
         $wrapper->checkbox('embed_content_encoded', array('label' => __('Include HTML Content', 'podlove'), 'description' => __('Include episode show notes in the feed.', 'podlove'), 'default' => false));
         $wrapper->subheader(__('Directory Settings', 'podlove'));
         $wrapper->checkbox('enable', array('label' => __('Allow Submission to Directories', 'podlove'), 'description' => __('Allow this feed to appear in podcast directories.', 'podlove'), 'default' => true));
         do_action('podlove_feeds_directories', $wrapper);
         $wrapper->string('itunes_feed_id', array('label' => __('iTunes Feed ID', 'podlove'), 'description' => __('Is used to generate a link to the iTunes directory.', 'podlove') . ($feed->itunes_feed_id ? ' <a href="http://itunes.apple.com/podcast/id' . $feed->itunes_feed_id . '" target="_blank">' . __('Open in iTunes directory') . '</a>' : ''), 'html' => array('class' => 'regular-text podlove-check-input')));
         $wrapper->subheader(__('Advanced Settings', 'podlove'));
         $wrapper->select('redirect_http_status', array('label' => __('Redirect Method', 'podlove'), 'description' => __('', 'podlove'), 'options' => array('0' => 'Don\'t redirect', '307' => 'Temporary Redirect (HTTP Status 307)', '301' => 'Permanent Redirect (HTTP Status 301)'), 'default' => 0, 'please_choose' => false));
         $wrapper->string('redirect_url', array('label' => __('Redirect Url', 'podlove'), 'description' => __('e.g. Feedburner URL', 'podlove'), 'html' => array('class' => 'regular-text podlove-check-input', 'data-podlove-input-type' => 'url')));
         $podcast_settings = get_option('podlove_podcast');
         if ($podcast_settings['limit_items'] < 0) {
             $limit_default = 'No limit';
         } else {
             $limit_default = $podcast_settings['limit_items'];
         }
         $limit_options = array('-2' => __("Use Podlove default (" . $limit_default . ")", 'podlove'), '-1' => __("No limit. Include all items.", 'podlove'), '0' => __('Use WordPress Default', 'podlove') . ' (' . get_option('posts_per_rss') . ')');
         for ($i = 1; $i * 5 <= 100; $i++) {
             $limit_options[$i * 5] = $i * 5;
         }
         $wrapper->select('limit_items', array('label' => __('Limit Items', 'podlove'), 'description' => __('If you have a lot of episodes, you might want to restrict the feed size.', 'podlove'), 'options' => $limit_options, 'please_choose' => false, 'default' => '-2'));
         $wrapper->subheader(__('Protection', 'podlove'));
         $wrapper->checkbox('protected', array('label' => __('Protect feed ', 'podlove'), 'description' => __('The feed will be protected by HTTP Basic Authentication.', 'podlove'), 'default' => false));
         $wrapper->select('protection_type', array('label' => __('Method', 'podlove'), 'description' => __('', 'podlove'), 'options' => array('0' => 'Custom Login', '1' => 'WordPress User database'), 'default' => -1, 'please_choose' => true));
         $wrapper->string('protection_user', array('label' => __('Username', 'podlove'), 'description' => '', 'html' => array('class' => 'regular-text required')));
         $wrapper->string('protection_password', array('label' => __('Password', 'podlove'), 'description' => '', 'html' => array('class' => 'regular-text required')));
         do_action('podlove_feed_settings_bottom', $wrapper);
     });
 }