md2bbc.pl 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #!/usr/bin/env perl
  2. ## Oriented for Hubzilla hub bbcode
  3. ## https://gist.github.com/Flashwalker/360e8615bff1b9b322e0096fe92680ab
  4. ## Origin: https://gist.github.com/RogerDodger/4405595
  5. ## Dependencies:
  6. ## sudo apt-get install libtext-markdown-perl libtext-typography-perl
  7. ## Usage:
  8. ## md2bbc.pl < "Markdown.md"
  9. use strict;
  10. use warnings;
  11. use 5.01;
  12. use Text::Markdown;
  13. use Encode;
  14. use HTML::Entities;
  15. use Getopt::Long;
  16. ## Ensure proper encoding of IO
  17. use open qw/:std :utf8/;
  18. binmode(STDIN, ':utf8');
  19. binmode(STDOUT, ':utf8');
  20. binmode(STDERR, ':utf8');
  21. ## Get options
  22. # my $opt = { code => 0, lists => 0, smartypants => 1 };
  23. # GetOptions($opt, qw/code lists smartypants!/);
  24. ## Read input
  25. my $in;
  26. my $fn = shift;
  27. if (defined $fn && -r $fn) {
  28. open READ, '<', $fn;
  29. $in = eval { local $/; <READ> };
  30. close READ;
  31. }
  32. else {
  33. $in = eval { local $/; <STDIN> };
  34. }
  35. ## Profit
  36. # print md2bbc($in, $opt);
  37. print md2bbc($in);
  38. sub md2bbc {
  39. local $_ = shift or return '';
  40. # my $opt = shift;
  41. ## Override the Text::Markdown method that handles lists to do
  42. ## nothing if we don't have BBCode lists supported
  43. # eval {
  44. # no warnings 'redefine';
  45. # sub Text::Markdown::_DoLists {
  46. # my( $self, $text ) = @_;
  47. # return $text;
  48. # }
  49. # } unless $opt->{lists};
  50. $_ = Text::Markdown->new->markdown($_);
  51. ## Smartypants operates first so that attributes (e.g., URLs) don't get converted
  52. # if ($opt->{smartypants}) {
  53. if (eval { require Text::SmartyPants }) {
  54. $_ = Text::SmartyPants::process($_, 2);
  55. }
  56. elsif (eval { require Text::Typography }) {
  57. $_ = Text::Typography::typography($_, 2);
  58. }
  59. # }
  60. ## Simple elements
  61. my %html2bb = (
  62. strong => 'b',
  63. b => 'b',
  64. em => 'i',
  65. i => 'i',
  66. strike => 's',
  67. u => 'u',
  68. sup => 'sup',
  69. sub => 'sub',
  70. );
  71. while (my($html, $bb) = each %html2bb) {
  72. s{<(/|)$html( [^>]*)?>}{[$1$bb]}g;
  73. }
  74. ## Undo anchors elements on unnamed links
  75. # s{<a
  76. # [^>]*? # random attributes we don't care about
  77. # href="(.+?)" # target
  78. # [^>]*? # more random attributes we don't care about
  79. # >
  80. # https?://.+? # $1 # https?://.+? # (.+?) # text
  81. # </a>
  82. # }{$1}xg;
  83. ## Convert links
  84. s{<a
  85. [^>]*? # random attributes we don't care about
  86. href="(.+?)" # target
  87. [^>]*? # more random attributes we don't care about
  88. >
  89. (.+?) # text
  90. </a>
  91. }{\#^[url=$1]$2\[/url]}xg;
  92. # }{[url="$1"]$2\[/url]}xg;
  93. ## Convert images
  94. # s{<img
  95. # [^>]*? # random attributes we don't care about
  96. # src="(.+?)" # target
  97. # [^>]*? # more random attributes we don't care about
  98. # alt="(.+?)" # alt
  99. # [^>]*? # more random attributes we don't care about
  100. # />
  101. # }{[img alt=$2]$1\[/img]}xg;
  102. ## Convert images
  103. s{<img
  104. [^>]*? # random attributes we don't care about
  105. src="(.+?)" # target
  106. [^>]*? # more random attributes we don't care about
  107. />
  108. }{[img]$1\[/img]}xg;
  109. # }{[img alt=$2]$1\[/img]}xg;
  110. ## Convert h1
  111. s{<h1>
  112. (.+?) # text
  113. </h1>
  114. }{[size=x-large][b]$1\[/b]\[/size]}xg;
  115. # }{[size=24][b]$1\[/b]\[/size]}xg;
  116. ## Convert h2
  117. s{<h2>
  118. (.+?) # text
  119. </h2>
  120. }{[size=large][b]$1\[/b]\[/size]}xg;
  121. # }{[size=18][b]$1\[/b]\[/size]}xg;
  122. ## Convert h3
  123. s{<h3>
  124. (.+?) # text
  125. </h3>
  126. }{[size=16][b]$1\[/b]\[/size]}xg;
  127. # }{[size=large][b]$1\[/b]\[/size]}xg;
  128. ## Convert h4
  129. s{<h4>
  130. (.+?) # text
  131. </h4>
  132. }{[b]$1\[/b]}xg;
  133. # }{[size=14][b]$1\[/b]\[/size]}xg;
  134. ## Convert hr
  135. # s{<hr ?/?>}{\n--------------------------------------------\n}g;
  136. ## Convert hr
  137. s{(^ *$)?\n?<hr ?/?>\n?(^ *$)?}{[hr]}g;
  138. ## Convert br
  139. s{(^ *$)?\n?<br ?/?>}{}g;
  140. # s{(^ *$)?\n?<br ?/?>}{}g;
  141. ## Convert blockquote
  142. s{(^ *$)?\n?<blockquote>\s*} {[quote]}g;
  143. s{( )?\s?</blockquote>\n?}{$1\[/quote]}xg;
  144. ## Undo paragraphs elements
  145. s{<p>}{}g;
  146. s{( )?\s?</p>}{$1}xg;
  147. ## Convert colored span elements
  148. # <span style="color: #888;">
  149. s{<span
  150. [^>]*? # random attributes we don't care about
  151. style=".*?color\s*:\s*([^;]+?)(;?|;.*?)" # color
  152. [^>]*? # more random attributes we don't care about
  153. >
  154. (.+?) # text
  155. </span>
  156. }{[color=$1]$3\[/color]}xg;
  157. ## Undo code elemeents
  158. # if ($opt->{code}) {
  159. s{(^ *$)?\n?<pre><code>} {[code]}g;
  160. s{</code></pre>\n?(^ *$)?} {[/code]}g;
  161. # }
  162. # else {
  163. # s{<pre><code>\s*} {}g;
  164. # s{\s*</code></pre>} {}g;
  165. # }
  166. ## Convert kbd element
  167. s{<kbd>} {[code]}g;
  168. s{</kbd>} {[/code]}g;
  169. # Convert list elements
  170. # if ($opt->{lists}) {
  171. s{(^ *$)?\n?<ul>\s*} {[list]}g;
  172. s{(^ *$)?\n?<ol>\s*} {[list=1]}g;
  173. s{\s*</[uo]l>\n?(^ *$)?} {[/list]}g;
  174. s{<li>} {[*]}g;
  175. s{</li>} {}g;
  176. # }
  177. ## Undo cutom elements
  178. # s{</?
  179. # [^>]*? # random attributes we don't care about
  180. # >
  181. # }{}g;
  182. ## Decode HTML entities
  183. return decode_entities $_;
  184. }