-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Mark George
committed
Sep 25, 2013
1 parent
1c01174
commit e97e182
Showing
17 changed files
with
347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
var Postwriter = { | ||
|
||
size_slider_changed: function( event, ui ) { | ||
Postwriter.describe_chain_size( ui.value ); | ||
}, | ||
|
||
describe_chain_size: function( value ) { | ||
if ( value < 0 || value > 10 ) | ||
return; | ||
|
||
jQuery( 'span#postwriter_chain_size_description' ).html( [ | ||
'F\'tang Crazy', | ||
'Extremely Random', | ||
'Very Random', | ||
'Random', | ||
'Less Random', | ||
'Barely Random', | ||
'Boring', | ||
'Yawn.' | ||
][ value - 1 ] ); | ||
}, | ||
|
||
}; | ||
|
||
jQuery( document ).ready( function() { | ||
|
||
Postwriter.chain_size_slider = jQuery( 'div#postwriter_chain_size' ).slider( { | ||
value: 4, | ||
min: 1, | ||
max: 8, | ||
step: 1, | ||
slide: Postwriter.size_slider_changed | ||
} ); | ||
|
||
Postwriter.describe_chain_size( 4 ); | ||
|
||
jQuery( 'span#postwriter_generate' ).click( function( event ) { | ||
jQuery( 'span#postwriter_loading' ).show(); | ||
jQuery( 'span#postwriter_generate' ).hide(); | ||
|
||
var chain_size = Postwriter.chain_size_slider.slider( 'value' ); | ||
var chain_by = jQuery( 'select#postwriter_chain_by option:selected' ).val(); | ||
|
||
var data = { | ||
action: 'postwriter_generate', | ||
chain_size: chain_size, | ||
chain_by: chain_by | ||
}; | ||
|
||
jQuery.post( ajaxurl, data, function( data ) { | ||
jQuery( 'span#postwriter_loading' ).hide(); | ||
jQuery( 'span#postwriter_generate' ).show(); | ||
|
||
try { | ||
var response = jQuery.parseJSON( data ); | ||
} catch ( e ) { | ||
var response = data; | ||
}; | ||
|
||
if ( 'object' == typeof( response ) && response.hasOwnProperty( 'title' ) && response.hasOwnProperty( 'body' ) ) { | ||
jQuery( 'input#title' ).val( response.title ).trigger( 'focus' ); | ||
|
||
if ( switchEditors && switchEditors.go ) | ||
switchEditors.go( null, 'html' ); | ||
|
||
jQuery( 'textarea#content' ).val( response.body ); | ||
} else { | ||
var error = response.error ? response.error : response; | ||
if ( ! error ) | ||
error = 'Empty response from the server :('; | ||
|
||
alert( error ); | ||
} | ||
} ); | ||
} ); | ||
|
||
} ); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,265 @@ | ||
<?php | ||
/* | ||
Plugin Name: Postwriter | ||
Plugin URI: http://thingalon.com/ | ||
Description: Ghostwrites new posts automatically, based on your past posts. Useful only for comedy value. | ||
Version: 0.1.0 | ||
Author: thingalon | ||
Author URI: http://thingalon.com | ||
License: GPLv2 or later | ||
*/ | ||
|
||
// Make sure we don't expose any info if called directly | ||
if ( !function_exists( 'add_action' ) ) { | ||
echo "Hi there! I'm just a plugin, not much I can do when called directly."; | ||
exit; | ||
} | ||
|
||
// Load javascript / enqueue hook for new post submit panel | ||
function postwriter_enqueue_admin_scripts( $hook ) { | ||
if ( 'post-new.php' == $hook ) { | ||
wp_register_script( 'postwriter_admin_script', plugins_url( '/admin.js', __FILE__ ), array( 'jquery', 'jquery-ui-core', 'jquery-ui-slider' ) ); | ||
wp_enqueue_script( 'postwriter_admin_script' ); | ||
|
||
wp_register_style( 'postwriter_jquery_ui', plugins_url( 'postwriter/jquery-ui.min.css', __FILE ) ); | ||
wp_enqueue_style( 'postwriter_jquery_ui' ); | ||
} | ||
} | ||
add_action( 'admin_enqueue_scripts', 'postwriter_enqueue_admin_scripts' ); | ||
|
||
function postwriter_add_custom_box() { | ||
add_meta_box( 'postwriter_metabox', __( 'Postwriter - Generate Random', 'postwriter' ), 'postwriter_populate_custom_box', 'post', 'side', 'high' ); | ||
} | ||
add_action( 'add_meta_boxes', 'postwriter_add_custom_box' ); | ||
|
||
function postwriter_populate_custom_box() { | ||
?> | ||
<div class="misc-pub-section"> | ||
<div> | ||
Chain by: | ||
<select id="postwriter_chain_by"> | ||
<option value="character">Character</option> | ||
<option value="word">Word (less random)</option> | ||
</select> | ||
</div> | ||
<div style="margin:10px 0px;"> | ||
Chain length: | ||
<div style="display:inline-block;width:50%;margin-left:10px;position:relative;text-align:center;"> | ||
<div id="postwriter_chain_size"></div> | ||
<span id="postwriter_chain_size_description"></span> | ||
</div> | ||
</div> | ||
<div style="float:right"> | ||
<span id="postwriter_generate"> | ||
<a href="#" class="button button-small">Generate Post</a> | ||
</span> | ||
<span id="postwriter_loading" style="display:none;"> | ||
<img src="images/wpspin_light.gif" alt="generating..." > | ||
Generating... | ||
</span> | ||
</div> | ||
<div style="clear:both;"></div> | ||
</div> | ||
<?php | ||
} | ||
|
||
// AJAX hook to generate and return a new post body. | ||
function postwriter_generate() { | ||
// Check parameters | ||
$body_markov_order = isset( $_POST['chain_size'] ) ? (int)$_POST['chain_size'] : 4; | ||
$body_tokenizer = ( isset( $_POST['chain_by'] ) && 'word' == $_POST['chain_by'] ) ? 'Postwriter_Word_Tokenizer' : 'Postwriter_Character_Tokenizer'; | ||
|
||
if ( $body_markov_order < 1 ) | ||
$body_markov_order = 1; | ||
elseif ( $body_markov_order > 8 ) | ||
$body_markov_order = 8; | ||
|
||
$body_length = ( 'Postwriter_Word_Tokenizer' == $body_tokenizer ) ? rand( 80, 500 ) : rand( 500, 1000 ); | ||
|
||
// Fetch 100 random posts to use as input | ||
$random_posts = get_posts( array( 'posts_per_page' => 100, 'orderby' => 'rand' ) ); | ||
if ( count( $random_posts ) < 10 ) { | ||
// Don't bother with less than 10 posts to work with. | ||
echo json_encode( array( 'error' => 'You need at least 10 posts to meaningfully generate new posts. You seem to have only ' . count( $random_posts ) . '.' ) ); | ||
die(); | ||
} | ||
|
||
// Create markov chainers with randomized properties | ||
$title_markov = new Postwriter_Markov_Chainer( 'Postwriter_Character_Tokenizer', rand( 3, 5 ) ); | ||
$body_markov = new Postwriter_Markov_Chainer( $body_tokenizer, $body_markov_order ); | ||
|
||
// Feed the found posts to the markov chainers | ||
foreach ( $random_posts as $post ) { | ||
$title_markov->feed_data( postwriter_strip_post( $post->post_title ) ); | ||
$body_markov->feed_data( postwriter_strip_post( $post->post_content ) ); | ||
} | ||
|
||
// Generate new post body/title | ||
$new_title = $title_markov->generate_data( rand( 20, 60 ), true ); | ||
$new_body = $body_markov->generate_data( $body_length ); | ||
|
||
echo json_encode( array( 'title' => $new_title, 'body' => $new_body ) ); | ||
die(); | ||
} | ||
add_action('wp_ajax_postwriter_generate', 'postwriter_generate'); | ||
|
||
// Strip the stuff we don't want to cope with out of source posts. | ||
function postwriter_strip_post( $post ) { | ||
$post = preg_replace( '[\(\)|"]', '', $post ); | ||
$post = trim( preg_replace( "/<pre[^>]*>.*?<\/pre>/s", "", $post ) ); | ||
$post = strip_tags( $post ); | ||
$post = strip_shortcodes( $post ); | ||
return $post; | ||
} | ||
|
||
// Base tokenizer class; contains behavior to generate a bunch of tokens, needs to be overridden | ||
class Postwriter_Tokenizer { | ||
public $string; | ||
public $cursor; | ||
|
||
function Postwriter_Tokenizer( $string = null ) { | ||
$this->string = $string; | ||
$this->cursor = 0; | ||
} | ||
|
||
function get_n_symbols( $n ) { | ||
$r = array(); | ||
for ( $i = 0; $i < $n; ++$i ) { | ||
$s = $this->get_next_symbol(); | ||
if ( $s === false ) | ||
return $r; | ||
|
||
$r []= $s; | ||
} | ||
|
||
return $r; | ||
} | ||
|
||
function join_symbols( $symbols ) { | ||
return implode( ' ', $symbols ); | ||
} | ||
}; | ||
|
||
// Word-by-word tokenizer. Splits out words and interesting symbols into tokens of their own. | ||
class Postwriter_Word_Tokenizer extends Postwriter_Tokenizer { | ||
function get_next_symbol() { | ||
if ( $this->cursor >= strlen( $this->string ) ) | ||
return false; | ||
|
||
$sym = ''; | ||
|
||
while ( $this->cursor < strlen( $this->string ) && ( ctype_alpha( $this->string{$this->cursor} ) || ( $this->string{$this->cursor} == "'" && count( $sym ) ) ) ) | ||
$sym .= $this->string{$this->cursor++}; | ||
|
||
if ( empty( $sym ) ) { | ||
while ( $this->cursor < strlen( $this->string ) && ctype_digit( $this->string{$this->cursor} ) ) | ||
$sym .= $this->string{$this->cursor++}; | ||
|
||
if ( $this->cursor < strlen( $this->string ) && empty( $sym ) ) | ||
$sym .= $this->string{$this->cursor++}; | ||
} | ||
|
||
while ( $this->cursor < strlen( $this->string ) && ctype_space( $this->string{$this->cursor} ) ) | ||
$this->cursor++; | ||
|
||
return $sym; | ||
} | ||
|
||
function join_symbols( $symbols ) { | ||
$string = implode( ' ', $symbols ); | ||
|
||
// Tidy it up a bit. | ||
$string = preg_replace( "#(\d) \. (\d)#", '$1.$2', $string ); // Decimal place. | ||
$string = preg_replace( "# ([.:,;!?]) #", "$1 ", $string ); // Full stops, commas, etc. | ||
$string = preg_replace( "# _ #", "_", $string ); // Underscores | ||
|
||
return $string; | ||
} | ||
}; | ||
|
||
// Character-by-character tokenizer. Blindly splits the input into individual characters. | ||
class Postwriter_Character_Tokenizer extends Postwriter_Tokenizer { | ||
function get_next_symbol() { | ||
if ( $this->cursor >= strlen( $this->string ) ) | ||
return false; | ||
|
||
return $this->string{$this->cursor++}; | ||
} | ||
|
||
function join_symbols( $symbols ) { | ||
return implode( '', $symbols ); | ||
} | ||
}; | ||
|
||
// Markov chainer: where the magic happens. Takes any textual input, and generates similar output. | ||
class Postwriter_Markov_Chainer { | ||
private $table; | ||
private $order; | ||
private $tokenizer_class; | ||
|
||
function Postwriter_Markov_Chainer( $tokenizer_class, $order ) { | ||
error_log( $tokenizer_class ); | ||
|
||
$this->tokenizer_class = $tokenizer_class; | ||
$this->order = $order; | ||
$this->table = array(); | ||
} | ||
|
||
// Push data into the markov chainer, using the configured tokenizer | ||
function feed_data( $input ) { | ||
$tokenizer = new $this->tokenizer_class( $input ); | ||
$from = array(); | ||
$to = $tokenizer->get_n_symbols( $this->order ); | ||
while ( count( $to ) > 0 ) { | ||
$from_key = serialize( $from ); | ||
$to_key = serialize( $to ); | ||
|
||
if ( ! isset( $this->table[ $from_key ] ) ) | ||
$this->table[ $from_key ] = array(); | ||
if ( ! isset( $this->table[ $from_key ][ $to_key ] ) ) | ||
$this->table[ $from_key ][ $to_key ] = 1; | ||
else | ||
$this->table[ $from_key ][ $to_key ]++; | ||
|
||
$from = $to; | ||
$to = $tokenizer->get_n_symbols( $this->order ); | ||
} | ||
} | ||
|
||
// Generate $length tokens of new data. | ||
function generate_data( $length, $end_on_hiccup = false ) { | ||
$key = serialize( array() ); | ||
$data = array(); | ||
|
||
while ( count( $data ) < $length ) { | ||
$next_key = null; | ||
if ( isset( $this->table[ $key ] ) ) | ||
$next_key = $this->weighted_lookup( $this->table[ $key ] ); | ||
|
||
if ( $next_key ) { | ||
$data = array_merge( $data, unserialize( $next_key ) ); | ||
} else { | ||
if ( $end_on_hiccup ) | ||
break; | ||
|
||
$next_key = serialize( array() ); | ||
} | ||
|
||
$key = $next_key; | ||
} | ||
|
||
$tok = new $this->tokenizer_class(); | ||
return $tok->join_symbols( $data ); | ||
} | ||
|
||
// Helper method to choose the next set of tokens, by weighted roulette. | ||
function weighted_lookup( $array ) { | ||
$total = array_sum( $array ); | ||
$rand = mt_rand( 1, $total ); | ||
foreach ( $array as $item => $weight ) { | ||
if ( $rand <= $weight ) | ||
return $item; | ||
$rand -= $weight; | ||
} | ||
} | ||
}; |