<commit_before><?php
namespace Podlove;
use \Podlove\Model;

function handle_direct_download() {
	
	if ( ! isset( $_GET['download_media_file'] ) )
		return;

	// tell WP Super Cache to not cache download links
	if ( ! defined( 'DONOTCACHEPAGE' ) )
		define( 'DONOTCACHEPAGE', true );

	$media_file_id = (int) $_GET['download_media_file'];
	$media_file    = Model\MediaFile::find_by_id( $media_file_id );

	if ( ! $media_file ) {
		status_header( 404 );
		exit;
	}

	$episode_asset = $media_file->episode_asset();

	if ( ! $episode_asset || ! $episode_asset->downloadable ) {
		status_header( 404 );
		exit;
	}

	if ( in_array( strtolower( ini_get( 'allow_url_fopen' ) ), array( "1", "on", "true" ) ) ) {
		header( "Expires: 0" );
		header( 'Cache-Control: must-revalidate' );
	    header( 'Pragma: public' );
		header( "Content-Type: application/force-download" );
		header( "Content-Description: File Transfer" );
		header( "Content-Disposition: attachment; filename=" . $media_file->get_download_file_name() );
		header( "Content-Transfer-Encoding: binary" );

		if ( $media_file->size > 0 )
			header( 'Content-Length: ' . $media_file->size );
		
		ob_clean();
		flush();
		while ( @ob_end_flush() ); // flush and end all output buffers
		readfile( $media_file->get_file_url() );
		exit;
	} else {
		header( "Location: " . $media_file->get_file_url() );
		exit;
	}
}
add_action( 'init', '\Podlove\handle_direct_download' );

/**
 * Provides a shortcode to display all available download links.
 *
 * Usage:
 *	[podlove-episode-downloads]
 *
 *  Attributes:
 *    style  "buttons" - list of buttons
 *           "select" (default) - html select list
 * 
 * @param  array $options
 * @return string
 */
function episode_downloads_shortcode( $options ) {
	global $post;

	if ( is_feed() )
		return '';

	$defaults = array( 'style' => 'select' );
	$attributes = shortcode_atts( $defaults, $options );

	$episode = Model\Episode::find_or_create_by_post_id( $post->ID );
	$media_files = $episode->media_files();
	$downloads = array();

	foreach ( $media_files as $media_file ) {

		$episode_asset = $media_file->episode_asset();

		if ( ! $episode_asset->downloadable )
			continue;

		$file_type = $episode_asset->file_type();
		
		$download_link_url  = get_bloginfo( 'url' ) . '?download_media_file=' . $media_file->id;
		$download_link_name = str_replace( " ", "&nbsp;", $episode_asset->title );

		$downloads[] = array(
			'url'  => $download_link_url,
			'name' => $download_link_name,
			'size' => \Podlove\format_bytes( $media_file->size, 0 ),
			'file' => $media_file
		);
	}

	if ( $attributes['style'] === 'buttons' ) {
		$html = '<ul class="episode_download_list">';
		foreach ( $downloads as $download ) {
			$html .= '  <li>';
			$html .= sprintf(
				'<a href="%s">%s%s</a>',
				apply_filters( 'podlove_download_link_url', $download['url'], $download['file'] ),
				apply_filters( 'podlove_download_link_name', $download['name'], $download['file'] ),
				'<span class="size">' . $download['size'] . '</span>'
			);
			$html .= '  </li>';
		}
		$html .= '</ul>';
	} else {
		$html = '<div class="episode_downloads">';
		$html.= 	'<select name="podlove_downloads">';
		foreach ( $downloads as $download ) {
			$html .= sprintf(
				'<option value="%s" data-raw-url="%s">%s [%s]</option>',
				apply_filters( 'podlove_download_link_url', $download['url'], $download['file'] ),
				$download['file']->get_file_url(),
				apply_filters( 'podlove_download_link_name', $download['name'], $download['file'] ),
				$download['size']
			);
		}
		$html.= 	'</select>';
		$html.= 	'<button class="primary">Download</button>';
		$html.= 	'<button class="secondary">Show URL</button>';
		// $html.= 	'<a href="#">Show URL</a>';
		$html.= '</div>';
	}

	return apply_filters( 'podlove_downloads_before', '' )
	     . $html
	     . apply_filters( 'podlove_downloads_after', '' );
}
add_shortcode( 'podlove-episode-downloads', '\Podlove\episode_downloads_shortcode' );

/**
 * 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();
	$asset_assignment = Model\AssetAssignment::get_instance();

	$formats_data = get_option( 'podlove_webplayer_formats' );

	if ( ! count( $formats_data ) )
		return;

	/**
	 * Look into the media files of an episode and return formats matching criteria:
	 * - the corresponding asset is configured in the web player
	 * - the file exists
	 * 
	 * @param   $formats array of format names like 'mp4', 'ogg'
	 * @param   $format_type 'audio' or 'video'
	 */
	$get_available_formats = function ( $formats, $format_type ) use ( $episode, $formats_data ) {

		$available_formats = array();

		foreach ( $formats as $format ) {

			if ( ! isset( $formats_data[ $format_type ][ $format ] ) )
				continue;

			$episode_asset = Model\EpisodeAsset::find_by_id( $formats_data[ $format_type ][ $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"', $format, $media_file->get_file_url() );
		}

		return $available_formats;
	};

	$is_video = true;
	$available_formats = $get_available_formats( array( 'mp4', 'ogg', 'webm' ), 'video' );

	// only look for audio if there is no video file
	if ( count( $available_formats ) === 0 ) {
		$is_video = false;
		$available_formats = $get_available_formats( array( 'mp3', 'mp4', 'ogg', 'opus' ), 'audio' );
	}

	$chapters = '';
	if ( $asset_assignment->chapters === 'manual' && $episode->chapters ) {
		$chapters = 'chapters="_podlove_chapters"';
	} elseif ( $asset_assignment->chapters > 0 ) {
		$chapter_asset = Model\EpisodeAsset::find_by_id( $asset_assignment->chapters );
		$media_file = Model\MediaFile::find_by_episode_id_and_episode_asset_id( $episode->id, $chapter_asset->id );
		if ( $media_file ) {
			$chapters = 'chapters="' . $media_file->get_file_url() . '"';
		}
	}
<commit_msg>handle missing chapter file for web player<commit_after><?php
namespace Podlove;
use \Podlove\Model;

function handle_direct_download() {
	
	if ( ! isset( $_GET['download_media_file'] ) )
		return;

	// tell WP Super Cache to not cache download links
	if ( ! defined( 'DONOTCACHEPAGE' ) )
		define( 'DONOTCACHEPAGE', true );

	$media_file_id = (int) $_GET['download_media_file'];
	$media_file    = Model\MediaFile::find_by_id( $media_file_id );

	if ( ! $media_file ) {
		status_header( 404 );
		exit;
	}

	$episode_asset = $media_file->episode_asset();

	if ( ! $episode_asset || ! $episode_asset->downloadable ) {
		status_header( 404 );
		exit;
	}

	if ( in_array( strtolower( ini_get( 'allow_url_fopen' ) ), array( "1", "on", "true" ) ) ) {
		header( "Expires: 0" );
		header( 'Cache-Control: must-revalidate' );
	    header( 'Pragma: public' );
		header( "Content-Type: application/force-download" );
		header( "Content-Description: File Transfer" );
		header( "Content-Disposition: attachment; filename=" . $media_file->get_download_file_name() );
		header( "Content-Transfer-Encoding: binary" );

		if ( $media_file->size > 0 )
			header( 'Content-Length: ' . $media_file->size );
		
		ob_clean();
		flush();
		while ( @ob_end_flush() ); // flush and end all output buffers
		readfile( $media_file->get_file_url() );
		exit;
	} else {
		header( "Location: " . $media_file->get_file_url() );
		exit;
	}
}
add_action( 'init', '\Podlove\handle_direct_download' );

/**
 * Provides a shortcode to display all available download links.
 *
 * Usage:
 *	[podlove-episode-downloads]
 *
 *  Attributes:
 *    style  "buttons" - list of buttons
 *           "select" (default) - html select list
 * 
 * @param  array $options
 * @return string
 */
function episode_downloads_shortcode( $options ) {
	global $post;

	if ( is_feed() )
		return '';

	$defaults = array( 'style' => 'select' );
	$attributes = shortcode_atts( $defaults, $options );

	$episode = Model\Episode::find_or_create_by_post_id( $post->ID );
	$media_files = $episode->media_files();
	$downloads = array();

	foreach ( $media_files as $media_file ) {

		$episode_asset = $media_file->episode_asset();

		if ( ! $episode_asset->downloadable )
			continue;

		$file_type = $episode_asset->file_type();
		
		$download_link_url  = get_bloginfo( 'url' ) . '?download_media_file=' . $media_file->id;
		$download_link_name = str_replace( " ", "&nbsp;", $episode_asset->title );

		$downloads[] = array(
			'url'  => $download_link_url,
			'name' => $download_link_name,
			'size' => \Podlove\format_bytes( $media_file->size, 0 ),
			'file' => $media_file
		);
	}

	if ( $attributes['style'] === 'buttons' ) {
		$html = '<ul class="episode_download_list">';
		foreach ( $downloads as $download ) {
			$html .= '  <li>';
			$html .= sprintf(
				'<a href="%s">%s%s</a>',
				apply_filters( 'podlove_download_link_url', $download['url'], $download['file'] ),
				apply_filters( 'podlove_download_link_name', $download['name'], $download['file'] ),
				'<span class="size">' . $download['size'] . '</span>'
			);
			$html .= '  </li>';
		}
		$html .= '</ul>';
	} else {
		$html = '<div class="episode_downloads">';
		$html.= 	'<select name="podlove_downloads">';
		foreach ( $downloads as $download ) {
			$html .= sprintf(
				'<option value="%s" data-raw-url="%s">%s [%s]</option>',
				apply_filters( 'podlove_download_link_url', $download['url'], $download['file'] ),
				$download['file']->get_file_url(),
				apply_filters( 'podlove_download_link_name', $download['name'], $download['file'] ),
				$download['size']
			);
		}
		$html.= 	'</select>';
		$html.= 	'<button class="primary">Download</button>';
		$html.= 	'<button class="secondary">Show URL</button>';
		// $html.= 	'<a href="#">Show URL</a>';
		$html.= '</div>';
	}

	return apply_filters( 'podlove_downloads_before', '' )
	     . $html
	     . apply_filters( 'podlove_downloads_after', '' );
}
add_shortcode( 'podlove-episode-downloads', '\Podlove\episode_downloads_shortcode' );

/**
 * 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();
	$asset_assignment = Model\AssetAssignment::get_instance();

	$formats_data = get_option( 'podlove_webplayer_formats' );

	if ( ! count( $formats_data ) )
		return;

	/**
	 * Look into the media files of an episode and return formats matching criteria:
	 * - the corresponding asset is configured in the web player
	 * - the file exists
	 * 
	 * @param   $formats array of format names like 'mp4', 'ogg'
	 * @param   $format_type 'audio' or 'video'
	 */
	$get_available_formats = function ( $formats, $format_type ) use ( $episode, $formats_data ) {

		$available_formats = array();

		foreach ( $formats as $format ) {

			if ( ! isset( $formats_data[ $format_type ][ $format ] ) )
				continue;

			$episode_asset = Model\EpisodeAsset::find_by_id( $formats_data[ $format_type ][ $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"', $format, $media_file->get_file_url() );
		}

		return $available_formats;
	};

	$is_video = true;
	$available_formats = $get_available_formats( array( 'mp4', 'ogg', 'webm' ), 'video' );

	// only look for audio if there is no video file
	if ( count( $available_formats ) === 0 ) {
		$is_video = false;
		$available_formats = $get_available_formats( array( 'mp3', 'mp4', 'ogg', 'opus' ), 'audio' );
	}

	$chapters = '';
	if ( $asset_assignment->chapters === 'manual' && $episode->chapters ) {
		$chapters = 'chapters="_podlove_chapters"';
	} elseif ( $asset_assignment->chapters > 0 ) {
		$chapter_asset = Model\EpisodeAsset::find_by_id( $asset_assignment->chapters );
		$media_file = Model\MediaFile::find_by_episode_id_and_episode_asset_id( $episode->id, $chapter_asset->id );
		if ( $media_file && $media_file->size > 0 ) {
			$chapters = 'chapters="' . $media_file->get_file_url() . '"';
		}
	}

{'fraction_non_alphanumeric': 0.17656475108051864, 'fraction_numerical': 0.002641267808548103, 'mean_word_length': 4.167493796526054, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 113, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 102, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2084658', 'n_tokens_mistral': 4885, 'n_tokens_neox': 4437, 'n_words': 894}