<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package Mojolicious::Plugin::StaticShare;
use Mojo::Base 'Mojolicious::Plugin';
use Mojo::File qw(path);
use Mojolicious::Types;
use Mojo::Path;
use Mojo::Util qw(encode);

our $VERSION = '0.055';
my $PKG = __PACKAGE__;

has [qw(app config)];
has root_url =&gt; sub { Mojo::Path-&gt;new(encode('UTF-8', shift-&gt;config-&gt;{root_url}))-&gt;leading_slash(1)-&gt;trailing_slash(1) };
has root_dir =&gt; sub { Mojo::Path-&gt;new(shift-&gt;config-&gt;{root_dir} // '.')-&gt;trailing_slash(1) };
has admin_pass =&gt; sub { shift-&gt;config-&gt;{admin_pass} };
has public_uploads =&gt; sub { !! shift-&gt;config-&gt;{public_uploads} };
has render_dir =&gt;  sub { shift-&gt;config-&gt;{render_dir} };
has dir_index =&gt; sub { shift-&gt;config-&gt;{dir_index} // [qw(README.md INDEX.md README.pod INDEX.pod)] };
has render_pod =&gt;  sub { shift-&gt;config-&gt;{render_pod} };
has render_markdown =&gt;  sub { shift-&gt;config-&gt;{render_markdown} };
has markdown_pkg =&gt; sub { shift-&gt;config-&gt;{markdown_pkg} // 'Text::Markdown::Hoedown' };
has markdown =&gt; sub {# parser object
   __internal__::Markdown-&gt;new(shift-&gt;markdown_pkg);
};
has is_markdown =&gt; sub { qr{[.]m(?:d(?:own)?|kdn?|arkdown)$}i };
has is_pod =&gt; sub { qr{[.]p(?:od|m|l)$} };
has mime =&gt; sub { Mojolicious::Types-&gt;new };

sub register {
  my ($self, $app, $args) = @_;
  $self-&gt;config($args);
  $self-&gt;app($app);
  
  require Mojolicious::Plugin::StaticShare::Templates
    and push @{$app-&gt;renderer-&gt;classes}, "$PKG\::Templates"
    and push @{$app-&gt;static-&gt;paths}, path(__FILE__)-&gt;sibling('StaticShare')-&gt;child('static') 
    unless ($self-&gt;render_dir // '') eq 0
          &amp;&amp; ($self-&gt;render_markdown // '') eq 0;
  
  my $route = $self-&gt;root_url-&gt;clone-&gt;merge('*pth');#"$args-&gt;{root_url}/*pth";
  my $r = $app-&gt;routes;
  $r-&gt;get($self-&gt;root_url-&gt;to_route)-&gt;to(namespace=&gt;$PKG, controller=&gt;"Controller", action=&gt;'get', pth=&gt;'', plugin=&gt;$self)-&gt;name("$PKG ROOT");
  $r-&gt;post($self-&gt;root_url-&gt;to_route)-&gt;to(namespace=&gt;$PKG, controller=&gt;"Controller", action=&gt;'post', pth=&gt;'', plugin=&gt;$self)-&gt;name("$PKG ROOT POST");
  $r-&gt;get($route-&gt;to_route)-&gt;to(namespace=&gt;$PKG, controller=&gt;"Controller", action=&gt;'get', plugin=&gt;$self )-&gt;name("$PKG GET");
  $r-&gt;post($route-&gt;to_route)-&gt;to(namespace=&gt;$PKG, controller=&gt;"Controller", action=&gt;'post', plugin=&gt;$self )-&gt;name("$PKG POST");

  $app-&gt;helper(i18n =&gt; sub { &amp;i18n(@_) });
  
  #POD
  $self-&gt;app-&gt;plugin(PODRenderer =&gt; {no_perldoc =&gt; 1})
    unless $self-&gt;app-&gt;renderer-&gt;helpers-&gt;{'pod_to_html'} &amp;&amp; ($self-&gt;render_pod // '') eq 0 ;
  
  return $app;
}

my %loc = (
  'ru-ru'=&gt;{
    'Not found'=&gt;"ĐťĐµ Đ˝Đ°ĐąĐ´ĐµĐ˝Đľ",
    'Error on path'=&gt;"ĐžŃĐ¸Đ±ĐşĐ° Đ˛",
    'Error'=&gt;"ĐžŃĐ¸Đ±ĐşĐ°",
    'Permission denied'=&gt;"ĐťĐµŃ‚ Đ´ĐľŃŃ‚ŃĐżĐ°",
    'Cant open directory'=&gt;"ĐťĐµŃ‚ Đ´ĐľŃŃ‚ŃĐżĐ° Đ˛ ĐżĐ°ĐżĐşŃ",
    'Share'=&gt;'ĐžĐ±Đ·ĐľŃ€',
    'Index of'=&gt;'ĐˇĐľĐ´ĐµŃ€Đ¶Đ°Đ˝Đ¸Đµ',
    'Dirs'=&gt;'ĐźĐ°ĐżĐşĐ¸',
    'Files'=&gt;'Đ¤Đ°ĐąĐ»Ń‹',
    'Name'=&gt;'ĐťĐ°Đ·Đ˛Đ°Đ˝Đ¸Đµ Ń„Đ°ĐąĐ»Đ°',
    'Size'=&gt;'Đ&nbsp;Đ°Đ·ĐĽĐµŃ€',
    'Last Modified'=&gt;'Đ”Đ°Ń‚Đ° Đ¸Đ·ĐĽĐµĐ˝ĐµĐ˝Đ¸ŃŹ',
    'Up'=&gt;'Đ’Ń‹ŃĐµ',
    'Down'=&gt;'ĐťĐ¸Đ¶Đµ',
    'Add uploads'=&gt;'Đ”ĐľĐ±Đ°Đ˛Đ¸Ń‚ŃŚ Ń„Đ°ĐąĐ»Ń‹',
    'Add dir'=&gt;'Đ”ĐľĐ±Đ°Đ˛Đ¸Ń‚ŃŚ ĐżĐ°ĐżĐşŃ',
    'root'=&gt;"ĐşĐľŃ€ĐµĐ˝ŃŚ",
    'Uploading'=&gt;'Đ—Đ°ĐłŃ€ŃĐ¶Đ°ĐµŃ‚ŃŃŹ',
    'file is too big'=&gt;'ŃĐ»Đ¸ŃĐşĐľĐĽ Đ±ĐľĐ»ŃŚŃĐľĐą Ń„Đ°ĐąĐ»',
    'path is not directory'=&gt;"Đ˝ĐµŃ‚ Ń‚Đ°ĐşĐľĐłĐľ ĐşĐ°Ń‚Đ°Đ»ĐľĐłĐ°/ĐżĐ°ĐżĐşĐ¸",
    'file already exists' =&gt; "Ń‚Đ°ĐşĐľĐą Ń„Đ°ĐąĐ» ŃĐ¶Đµ ĐµŃŃ‚ŃŚ",
    'new dir name'=&gt;"Đ¸ĐĽŃŹ Đ˝ĐľĐ˛ĐľĐą ĐżĐ°ĐżĐşĐ¸",
    'Confirm to delete these files'=&gt;"ĐźĐľĐ´Ń‚Đ˛ĐµŃ€Đ´Đ¸Ń‚Đµ ŃĐ´Đ°Đ»ĐµĐ˝Đ¸Đµ ŃŤŃ‚Đ¸Ń… Ń„Đ°ĐąĐ»ĐľĐ˛",
     'Confirm to delete these dirs'=&gt;"ĐźĐľĐ´Ń‚Đ˛ĐµŃ€Đ´Đ¸Ń‚Đµ ŃĐ´Đ°Đ»ĐµĐ˝Đ¸Đµ ŃŤŃ‚Đ¸Ń… ĐżĐ°ĐżĐľĐş", 
    'I AM SURE'=&gt;"Đ”Đ",
  },
);
sub i18n {# helper
  my ($c, $str, $lang) = @_;
  #~ $lang //= $c-&gt;stash('language');
  return $str
    unless $c-&gt;stash('language');
  my $loc;
  for ($c-&gt;stash('language')-&gt;languages) {
    return $str
      if /en/;
    $loc = $loc{$_} || $loc{lc $_} || $loc{lc "$_-$_"}
      and last;
  }
  return $loc-&gt;{$str} || $loc-&gt;{lc $str} || $str
    if $loc;
  return $str;
}

##############################################
package __internal__::Markdown;
sub new {
  my $class  = shift;
  my $pkg = shift;
  return
    unless eval "require $pkg;  1";#
  #~ $pkg-&gt;import
    #~ if $pkg-&gt;can('import');
  return $pkg-&gt;new()
    if $pkg-&gt;can('new') &amp;&amp; $pkg-&gt;can('parse');
  return
    unless $pkg-&gt;can('markdown');
  bless {pkg=&gt;$pkg} =&gt; $class;
}

sub parse { my $self = shift; no strict 'refs'; ($self-&gt;{pkg}.'::markdown')-&gt;(@_); }

1;
=pod

=encoding utf8

Đ”ĐľĐ±Ń€ĐľĐłĐľ Đ˛ŃĐµĐĽ

=head1 Mojolicious::Plugin::StaticShare

Âˇ Âˇ Âˇ ALL GLORY TO GLORIA ! ! !

=head1 NAME

Mojolicious::Plugin::StaticShare - browse, upload, copy, move, delete static files and dirs.

=head1 VERSION

0.055

=head1 SYNOPSIS

  # Mojolicious
  $self-&gt;plugin('StaticShare', &lt;options&gt;);

  # Mojolicious::Lite
  plugin 'StaticShare', &lt;options&gt;;
  
  # oneliner
  $ perl -MMojolicious::Lite -E 'plugin("StaticShare", root_url=&gt;"/my/share",)-&gt;secrets([rand])-&gt;start' daemon


=head1 DESCRIPTION

This plugin for share static files/dirs and has public and admin functionality:

=head2 Public interface

Can browse and upload files if name not exists.

=head2 Admin interface

Can copy, move, delete files/dirs.

Append param C&lt;&lt; admin=&lt;admin_pass&gt; option &gt;&gt; to any url inside B&lt;root_url&gt; requests (see below).

=head1 OPTIONS

=head2 root_dir

Absolute or relative file system path root directory. Defaults to '.'.

  root_dir =&gt; '/mnt/usb',
  root_dir =&gt; 'foo', 

=head2 root_url

This prefix to url path. Defaults to '/'.

  root_url =&gt; '/', # mean route '/*pth'
  root_url =&gt; '', # mean also route '/*pth'
  root_url =&gt; '/my/share', # mean route '/my/share/*pth'

See L&lt;Mojolicious::Guides::Routing#Wildcard-placeholders&gt;.

=head2 admin_pass

Admin password (be sure https) for admin tasks. None defaults.

  admin_pass =&gt; '$%^!!9nes--', # 

Signin to admin interface C&lt; https://myhost/my/share/foo/bar?admin=$%^!!9nes-- &gt;

=head2 render_dir

Template path, format, handler, etc  which render directory index. Defaults to builtin things.

  render_dir =&gt; 'foo/dir_index', 
  render_dir =&gt; {template =&gt; 'foo/my_directory_index', foo=&gt;...},
  # Disable directory index rendering
  render_dir =&gt; 0,

=head3 Usefull stash variables

C&lt;pth&gt;, C&lt;url_path&gt;, C&lt;file_path&gt;, C&lt;language&gt;, C&lt;dirs&gt;, C&lt;files&gt;, C&lt;index&gt;

=head4 pth

Path of request exept C&lt;root_url&gt; option, as L&lt;Mojo::Path&gt; object.

=head4 url_path

Path of request with C&lt;root_url&gt; option, as L&lt;Mojo::Path&gt; object.

=head4 language

Req header AcceptLanguage as L&lt;HTTP::AcceptLanguage&gt; object.

=head4 dirs

List of scalars dirnames. Not sorted.

=head4 files

List of hashrefs (C&lt;name, size, mtime&gt; keys) files. Not sorted.

=head4 index

Filename for markdown or pod rendering in page below dirs and files.

=head2 render_markdown

Same as B&lt;render_dir&gt; but for markdown files. Defaults to builtin things.

  render_markdown =&gt;  'foo/markdown',
  render_markdown =&gt; {template =&gt; 'foo/markdown', foo=&gt;...},
  # Disable markdown rendering
  render_markdown =&gt; 0,

=head2 markdown_pkg

Module name for render markdown. Must contains sub C&lt;markdown($str)&gt; or method C&lt;parse($str)&gt;. Defaults to L&lt;Text::Markdown::Hoedown&gt;.

  markdown_pkg =&gt;  'Foo::Markup';

Does not need to install if C&lt;&lt; render_markdown =&gt; 0 &gt;&gt; or never render md files.

=head2 render_pod

Template path, format, handler, etc  which render pod files. Defaults to builtin things.

  render_pod=&gt;'foo/pod',
  render_pod =&gt; {template =&gt; 'foo/pod', layout=&gt;'pod', foo=&gt;...},
  # Disable pod rendering
  render_pod =&gt; 0,

=head2 dir_index

Arrayref to match files to include to directory index page. Defaults to C&lt;&lt; [qw(README.md INDEX.md README.pod INDEX.pod)] &gt;&gt;.

  dir_index =&gt; [qw(DIR.md)],
  dir_index =&gt; 0, # disable include markdown to index dir page

=head2 public_uploads

Boolean to disable/enable uploads for public users. Defaults to undef (disable).

  public_uploads=&gt;1, # enable

=head1 UTF-8

Everywhere  and everything: module, files, content.

=head1 WINDOWS OS

It was not tested but I hope you dont worry and have happy.

=head1 Extended markdown &amp; pod

You can place classnames and css-style rules to markup elements as below.

In markdown:

  # {.class1 .class2 padding: 0 0.5rem;} Header 1
  {.brown-text} brown paragraph text ...

In pod:

  =head2 {.class1 .blue-text border-bottom: 1px dotted;} Header 2
  
  {.red-text} red color text...

=head1 METHODS

L&lt;Mojolicious::Plugin::StaticShare&gt; inherits all methods from
L&lt;Mojolicious::Plugin&gt; and implements the following new ones.

=head2 register

  $plugin-&gt;register(Mojolicious-&gt;new);

Register plugin in L&lt;Mojolicious&gt; application.

=head1 SEE ALSO

L&lt;Mojolicious::Plugin::Directory&gt;

L&lt;Mojolicious&gt;, L&lt;Mojolicious::Guides&gt;, L&lt;http://mojolicious.org&gt;.

=head1 AUTHOR

ĐśĐ¸Ń…Đ°Đ¸Đ» Đ§Đµ (Mikhail Che), C&lt;&lt; &lt;mche[-at-]cpan.org&gt; &gt;&gt;

=head1 BUGS / CONTRIBUTING

Please report any bugs or feature requests at L&lt;https://github.com/mche/Mojolicious-Plugin-StaticShare/issues&gt;. Pull requests also welcome.

=head1 COPYRIGHT

Copyright 2017 Mikhail Che.

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut
</pre></body></html>