public function widget($args, $instance) { $number_of_episodes = is_numeric($instance['number_of_episodes']) ? $instance['number_of_episodes'] : 10; // Fallback for old browsers that allow a non-numeric string to be entered in the "number_of_episodes" field $episodes = array_slice(Episode::find_all_by_time(['post_status' => ['private', 'publish']]), 0, $number_of_episodes); echo $args['before_widget']; if (!empty($instance['title'])) { echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title']; } echo "<ul style='list-style-type: none;'>"; foreach ($episodes as $episode) { $post = get_post($episode->post_id); $episode_duration = new \Podlove\Duration($episode->duration); ?> <li> <?php if ($instance['show_image']) { ?> <img src="<?php echo $episode->cover_art_with_fallback()->setWidth(400)->url(); ?> " alt="<?php echo $post->post_title; ?> " style="width: 20%; vertical-align: top; margin-right: 2%;"/> <div style="display: inline-block; width: 75%;"> <?php } ?> <p> <a href="<?php echo post_permalink($episode->post_id); ?> "><?php echo $post->post_title; ?> </a><br /> <i class="podlove-icon-calendar"></i> <?php echo get_the_date(get_option('date_format'), $episode->post_id); ?> <?php if ($instance['show_duration']) { echo "<br /><i class='podlove-icon-time'></i> " . $episode_duration->get('human-readable'); } ?> </p> <?php if ($instance['show_image']) { ?> </div> <?php } ?> </li> <?php } echo "</ul>"; echo $args['after_widget']; }
public function episode_relation_form_callback($form_base_name = '_podlove_meta') { $existing_episodes = array(); foreach (\Podlove\Model\Episode::find_all_by_time() as $episode) { $existing_episodes[$episode->id] = get_the_title($episode->post_id); } $episode = \Podlove\Model\Episode::find_one_by_post_id(get_the_ID()); $existing_episode_relations = array_map(function ($episode) { return $episode->to_array(); }, \Podlove\Modules\RelatedEpisodes\Model\EpisodeRelation::get_related_episodes($episode->id)); ?> <div id="episode-relation-form"> <table class="podlove_alternating" border="0" cellspacing="0"> <thead> <tr> <th><?php _e('Episode', 'podlove'); ?> </th> <th><?php _e('Remove', 'podlove'); ?> </th> </tr> </thead> <tbody id="episode_relation_table_body" style="min-height: 50px;"> <tr class="episode_relation_table_body_placeholder" style="display: none;"> <td><em><?php echo __('No episode relations were added yet.', 'podlove'); ?> </em></td> </tr> </tbody> </table> <div id="add_new_episode_relation_wrapper"> <input class="button" id="add_new_episode_relation_button" value="+" type="button" /> </div> </div> <script type="text/template" id="episode-relation-row-template"> <tr class="podlove-episode-relation-table"> <td> <select name="<?php echo $form_base_name; ?> [related_episodes][{{id}}]" id="<?php echo $form_base_name; ?> _related_episodes_{{id}}" class="chosen-related-episodes podlove_episode_relation_episodes_dropdown"> <?php foreach ($existing_episodes as $episode_id => $episode_title) { ?> <option value="<?php echo $episode_id; ?> "><?php echo $episode_title; ?> </option> <?php } ?> </select> </td> <td> <span class="episode_relation_remove"> <i class="clickable podlove-icon-remove"></i> </span> </td> </tr> </script> <script type="text/javascript"> var PODLOVE = PODLOVE || {}; PODLOVE.related_episodes_existing_episode_relations = <?php echo json_encode($existing_episode_relations); ?> ; </script> <?php }
public static function prepare_statistics() { if (($statistics = get_transient('podlove_dashboard_stats')) !== FALSE) { return $statistics; } else { $episodes = Model\Episode::find_all_by_time(); $prev_post = 0; $counted_episodes = 0; $time_stamp_differences = array(); $episode_durations = array(); $episode_status_count = array('publish' => 0, 'private' => 0, 'future' => 0, 'draft' => 0); $statistics = array('episodes' => array(), 'total_episode_length' => 0, 'average_episode_length' => 0, 'days_between_releases' => 0, 'average_media_file_size' => 0, 'total_media_file_size' => 0); foreach ($episodes as $episode_key => $episode) { $post = get_post($episode->post_id); $counted_episodes++; // duration in seconds if (self::duration_to_seconds($episode->duration) > 0) { $episode_durations[$post->ID] = self::duration_to_seconds($episode->duration); } // count by post status if (!isset($episode_status_count[$post->post_status])) { $episode_status_count[$post->post_status] = 1; } else { $episode_status_count[$post->post_status]++; } // determine time in days since last publication if ($prev_post) { $timestamp_current_episode = new \DateTime($post->post_date); $timestamp_next_episode = new \DateTime($prev_post->post_date); $time_stamp_differences[$post->ID] = $timestamp_current_episode->diff($timestamp_next_episode)->days; } $prev_post = $post; } // Episode Stati $statistics['episodes'] = $episode_status_count; // Number of Episodes $statistics['total_number_of_episodes'] = count($episodes); // Total Episode length $statistics['total_episode_length'] = array_sum($episode_durations); // Calculating average episode in seconds $statistics['average_episode_length'] = count($episode_durations) > 0 ? round(array_sum($episode_durations) / count($episode_durations)) : 0; // Calculate average time until next release in days $statistics['days_between_releases'] = count($time_stamp_differences) > 0 ? round(array_sum($time_stamp_differences) / count($time_stamp_differences)) : 0; // Media Files $episodes_to_media_files = function ($media_files, $episode) { return array_merge($media_files, $episode->media_files()); }; $media_files = array_reduce($episodes, $episodes_to_media_files, array()); $valid_media_files = array_filter($media_files, function ($m) { return $m->size > 0; }); $sum_mediafile_sizes = function ($result, $media_file) { return $result + $media_file->size; }; $statistics['total_media_file_size'] = array_reduce($valid_media_files, $sum_mediafile_sizes, 0); $mediafile_count = count($valid_media_files); $statistics['average_media_file_size'] = $mediafile_count > 0 ? $statistics['total_media_file_size'] / $mediafile_count : 0; set_transient('podlove_dashboard_stats', $statistics, 3600); return $statistics; } }
public function column_episodes($podcast) { return $podcast->with_blog_scope(function () { return count(Episode::find_all_by_time()); }); }
public function load() { $this->api = new API_Wrapper($this); $module_url = $this->get_module_url(); $user = null; $selected_role = $this->get_module_option('adn_contributor_filter_role'); $selected_group = $this->get_module_option('adn_contributor_filter_group'); add_action('podlove_module_was_activated_app_dot_net', array($this, 'was_activated')); add_action('wp_ajax_podlove-refresh-channel', array($this, 'ajax_refresh_channel')); add_action('wp_ajax_podlove-adn-post', array($this, 'ajax_post_to_adn')); add_action('wp_ajax_podlove-preview-adn-post', array($this, 'ajax_preview_alpha_post')); if ($this->get_module_option('adn_auth_key') !== "") { add_action('publish_podcast', array($this, 'post_to_adn_handler')); add_action('publish_future_podcast', array($this, 'post_to_adn_handler')); add_action('delayed_adn_post', array($this, 'post_to_adn'), 10, 2); } if (isset($_GET["page"]) && $_GET["page"] == "podlove_settings_modules_handle") { add_action('admin_bar_init', array($this, 'reset_adn_auth')); } // Import all posts as already published add_filter('wp_import_post_meta', function ($postmetas, $post_id, $post) { $postmetas[] = array('key' => '_podlove_episode_was_published', 'value' => true); return $postmetas; }, 10, 3); if ($this->get_module_option('adn_auth_key') == "") { $description = '<i class="podlove-icon-remove"></i> ' . __('You need to allow Podlove Publisher to access your App.net account. To do so please start the authorization process, follow the instructions and paste the obtained code in the field above.', 'podlove') . '<br><a href="https://auth.podlove.org/adn.php?step=1" class="button button-primary" target="_blank">' . __('Start authorization process now', 'podlove') . '</a>'; $this->register_option('adn_auth_key', 'string', array('label' => __('Authorization', 'podlove'), 'description' => $description, 'html' => array('class' => 'regular-text podlove-check-input', 'placeholder' => 'App.net authentication code'))); } else { if ($user = $this->api->fetch_authorized_user()) { $description = '<i class="podlove-icon-ok"></i> ' . sprintf(__('You are logged in as %s. If you want to logout, click %shere%s.', 'podlove'), '<strong>' . $user->username . '</strong>', '<a href="' . admin_url('admin.php?page=podlove_settings_modules_handle&reset_appnet_auth_code=1') . '">', '</a>'); } else { $description = '<i class="podlove-icon-remove"></i> ' . sprintf(__('Something went wrong with the App.net connection. Please start the authorization process again. To do so click %shere%s', 'podlove'), '<a href="' . admin_url('admin.php?page=podlove_settings_modules_handle&reset_appnet_auth_code=1') . '">', '</a>'); } $this->register_option('adn_auth_key', 'hidden', array('label' => __('Authorization', 'podlove'), 'description' => $description, 'html' => array('class' => 'regular-text podlove-check-input'))); $this->register_option('adn_language_annotation', 'select', array('label' => __('Language of Announcement', 'podlove'), 'description' => 'Selecting the language of the Announcement, will include an <a href="http://developers.app.net/docs/meta/annotations/" target="_blank">App.net language annotation</a>.', 'html' => array('class' => 'regular-text adn-dropdown'), 'options' => $this->get_languages())); $this->register_option('adn_patter_room_announcement', 'checkbox', array('label' => __('Patter', 'podlove'), 'description' => 'Post announcement to Patter room, too.')); $this->register_option('adn_patter_room', 'select', array('description' => '<span class="podlove_adn_patter_refresh" data-category="patter_room"><i class="podlove-icon-repeat"></i></span>From the list of subscribed <a href="http://patter-app.net/faq.html" target="_blank">Patter rooms</a>, choose the one related to your Podcast.', 'html' => array('class' => 'regular-text adn-dropdown'), 'options' => $this->api->fetch_patter_rooms())); $this->register_option('adn_broadcast', 'checkbox', array('label' => __('Broadcast', 'podlove'), 'description' => 'Send announcement via App.net Broadcast Channel.')); $this->register_option('adn_broadcast_channel', 'select', array('description' => '<span class="podlove_adn_broadcast_refresh" data-category="broadcast_channel"><i class="podlove-icon-repeat"></i></span> From the list of your Broadcast channels, choose the one related to your Podcast.', 'html' => array('class' => 'regular-text adn-dropdown'), 'options' => $this->api->fetch_broadcast_channels())); $this->register_option('adn_automatic_announcement', 'checkbox', array('label' => __('Automatic Announcement', 'podlove'), 'description' => 'Announces new podcast episodes on App.net')); $adn_post_delay_hours = str_pad($this->get_module_option('adn_post_delay_hours'), 2, 0, STR_PAD_LEFT); $adn_post_delay_minutes = str_pad($this->get_module_option('adn_post_delay_minutes'), 2, 0, STR_PAD_LEFT); $this->register_option('adn_post_delay', 'callback', array('label' => __('Post delay', 'podlove'), 'callback' => function () use($adn_post_delay_hours, $adn_post_delay_minutes) { ?> <input type="text" name="podlove_module_app_dot_net[adn_post_delay_hours]" id="podlove_module_app_dot_net_adn_post_delay_hours" value="<?php echo $adn_post_delay_hours ? $adn_post_delay_hours : ''; ?> " class="regular-text podlove-check-input" placeholder="00" > <label for="podlove_module_app_dot_net_adn_post_delay_hours">Hours</label> <input type="text" name="podlove_module_app_dot_net[adn_post_delay_minutes]" id="podlove_module_app_dot_net_adn_post_delay_minutes" value="<?php echo $adn_post_delay_minutes ? $adn_post_delay_minutes : ''; ?> " class="regular-text podlove-check-input" placeholder="00" > <label for="podlove_module_app_dot_net_adn_post_delay_minutes">Minutes</label> <?php })); $description = ''; if ($this->get_module_option('adn_poster_announcement_text') == "") { $description = '<i class="podlove-icon-remove"></i>' . __('You need to set a text to announce new episodes.', 'podlove'); } $description .= __('App.net allows 256 characters per post. Try to keep the announcement text short. Your episode titles will need more space than the placeholders.', 'podlove'); $description .= ' ' . __('Use these placeholders to customize your announcement', 'podlove') . ': <code title="' . __('The title of your podcast', 'podlove') . '">{podcastTitle}</code> <code title="' . __('The title of your episode, linking to it', 'podlove') . '">{linkedEpisodeTitle}</code> <code title="' . __('The title of the episode', 'podlove') . '">{episodeTitle}</code> <code title="' . __('The permalink of the current episode', 'podlove') . '">{episodeLink}</code> <code title="' . __('The subtitle of the episode', 'podlove') . '">{episodeSubtitle}</code>'; $preview_text = $this->get_module_option('adn_poster_announcement_text'); $this->register_option('adn_poster_announcement_text', 'callback', array('label' => __('Announcement text', 'podlove'), 'callback' => function () use($description, $preview_text) { $description = apply_filters('podlove_adn_tags_description', $description); ?> <div> <textarea name="podlove_module_app_dot_net[adn_poster_announcement_text]" class"podlove-check-input" id="podlove_module_app_dot_net_adn_poster_announcement_text" cols="50" rows="4" placeholder="Check out the new {podcastTitle} episode: {linkedEpisodeTitle}"><?php echo $preview_text; ?> </textarea> </div> <span class="description"><?php echo $description; ?> </span> <?php })); $this->register_option('adn_poster_image_fallback', 'checkbox', array('label' => __('Announcement Image', 'podlove'), 'description' => 'Use Podcast Cover as Fallback')); $this->register_option('adn_preview', 'callback', array('label' => __('Announcement preview', 'podlove'), 'callback' => function () use($selected_role, $selected_group, $user, $module_url) { if (!$user) { return; } $podcast = Model\Podcast::get(); if ($episode = Model\Episode::find_one_by_where('slug IS NOT NULL')) { $example_data = array('episode' => get_the_title($episode->post_id), 'episode-link' => get_permalink($episode->post_id), 'subtitle' => $episode->subtitle, 'episode-image' => $episode->cover_art() ? $episode->cover_art()->url() : '', 'podcast-image' => $podcast->cover_art()->url(), 'contributors' => ''); $example_data = apply_filters('podlove_adn_example_data', $example_data, $episode->post_id, $selected_role, $selected_group); } else { $example_data = array('episode' => 'My Example Episode', 'episode-link' => 'http://www.example.com/episode/001', 'subtitle' => 'My Example Subtitle', 'contributors' => '@example @elpmaxe', 'podcast-image' => '', 'episode-image' => ''); } ?> <div id="podlove_adn_post_preview" data-podcast="<?php echo $podcast->title; ?> " data-episode="<?php echo $example_data['episode']; ?> " data-episode-link="<?php echo $example_data['episode-link']; ?> " data-episode-subtitle="<?php echo $example_data['subtitle']; ?> " data-contributors="<?php echo $example_data['contributors']; ?> " data-episode-image="<?php echo $example_data['episode-image']; ?> " data-podcast-image="<?php echo $example_data['podcast-image']; ?> "> <div class="adn avatar" style="background-image:url(<?php echo $user->avatar_image->url; ?> );"></div> <div class="adn content"> <div class="adn image"><img src="" /></div> <div class="adn username"><?php echo $user->username; ?> </div> <div class="adn body">Lorem ipsum dolor ...</div> <div class="adn footer"> <ul> <li> <i class="podlove-icon-time"></i> now </li> <li> <i class="podlove-icon-reply"></i> Reply </li> <li> <i class="podlove-icon-share"></i> via Podlove Publisher </li> </ul> </div> </div> <div style="clear: both"></div> </div> <script type="text/javascript" src="<?php echo $module_url; ?> /adn.js"></script> <link rel="stylesheet" type="text/css" href="<?php echo $module_url; ?> /adn.css" /> <?php })); $this->register_option('adn_manual_post', 'callback', array('label' => __('Manual Announcement', 'podlove'), 'callback' => function () { ?> <select id="adn_manual_post_episode_selector" class="chosen"> <?php $episodes = Model\Episode::find_all_by_time(); foreach ($episodes as $episode) { $post = get_post($episode->post_id); echo "<option value='" . $episode->post_id . "'>" . $post->post_title . "</option>"; } ?> </select> <span class="button" id="adn_manual_post_alpha"> Announce, as configured <span class="adn-post-status-pending"> <i class="podlove-icon-spinner rotate"></i> </span> <span class="adn-post-status-ok"> <i class="podlove-icon-ok"></i> </span> </span> <?php })); } }
* contents into local field. */ add_filter('pre_update_option_podlove_asset_assignment', function ($new, $old) { global $wpdb; if (!isset($old['chapters']) || !isset($new['chapters'])) { return $new; } if ($new['chapters'] != 'manual') { // just changes to manual return $new; } if ((int) $old['chapters'] <= 0) { // just changes from an asset return $new; } $episodes = \Podlove\Model\Episode::find_all_by_time(); // 10 seconds per episode or 30 seconds since 1 request per asset // is required if it is not cached set_time_limit(max(30, count($episodes) * 10)); foreach ($episodes as $episode) { if ($chapters = $episode->get_chapters('mp4chaps')) { $episode->update_attribute('chapters', esc_sql($chapters)); } } // delete chapters caches $wpdb->query('DELETE FROM `' . $wpdb->options . '` WHERE option_name LIKE "%podlove_chapters_string_%"'); return $new; }, 10, 2); // extend episode form add_filter('podlove_episode_form_data', function ($form_data, $episode) { if (Model\AssetAssignment::get_instance()->chapters !== 'manual') {