Account created on 7 March 2019, almost 7 years ago
#

Recent comments

🇩🇰Denmark Steven Snedker

The problem should not affect the very soon to be published version 1.1.1.

🇩🇰Denmark Steven Snedker

I'll fix it ASAP. Before next year.

🇩🇰Denmark Steven Snedker

Looks great! Do remember to also update the README.md, while you're at it.

As far as I'm concerned, the README.md should just be a link to the project page .

The project page is read by way more people and is way faster to update.

But, who knows, maybe some people are keen users of the README.md.

🇩🇰Denmark Steven Snedker

This is a great module. Very well made. Getting all the button labels into the Drupal translation system was a good move.

Having half the button labels be configurable in the block settings is a nice move as well.

But why not have "Pause" and "Resume" be configurable in the block settings as well?
Newbies might not guess that they'll be able to change the labels in the translation system.

🇩🇰Denmark Steven Snedker

Chrome has made some great improvements to their multilingual voices. There are now four Danish voices, and they're all way better than what we had last year. Also, they now work on Windows, Mac and Linux.

Edge still has rather good voices for over a hundred languages.

Firefox... Not backed by billion-dollar companies. Mute is the best voice for Firefox.

🇩🇰Denmark Steven Snedker

Having

  • Image
  • Video

ads seems like a sensible minimum requirement for the SimpleAds module.

I haven't used

  • HTML5 (upload a zip-file)
  • Responsive (three images)

and I wonder if a lot of people use them.

We do not need

  • Animated gifs
  • Flash

any more, as the browsers have dropped the support.

I can't quite suss out if anyone would be happpier if the SimpleAds module just showed nodes instead of images or videos. That looks like an unwelcome additional layer of abstraction for most people. Just uploading an iamge or a vide oand setting a destination is probably what 90% of the users want.

But it looks as if SimpleAds is more or less an abandoned module.

🇩🇰Denmark Steven Snedker

This would also benefit the External Link Preview Module immensely.

Yet with all the awful specious invoicing companies out there, local caching could mean a lot of Drupal sites losing a lot of money and a lot of sleep. We're at an impasse at Make a local image copy for GDPR 📌 Make a local image copy for GDPR Active (read and shudder).

Wayback Filter could branch out and support way smaller archive sites like Archive.today or Ghost Archive. There may be a few other OKish candidates on the List of web archiving initiatives. Autosubmit the URL where feasible.

But with only 14 users , half of them me, and archive.org in ok health, I haven't spent any time on it. With only one user ever (!), Wayback Submit to Archive.org will never be updated.

But back to the orignal question: caching sites?
No. Having Drupal sites caching (storing and publishing) third party sites locally is sadly way too risky.

🇩🇰Denmark Steven Snedker

I was very happy when I made the module 12 years ago. It's ultra lightweight and solves a real problem elegantly for millions of people.

Somehow, no-one else cared about it. Two installations (probably both my own) for a decade, and a steadfast, opaque decision of the almighty archive.org NOT to write a single word about it ever. Even if prompted lovingly annually. Since 2014. Archive.org must find thousands of incoming links somehow unpalatable.
Archive.org have, however, written quite extensively about the Wayback bot running on the Wikipedias.

I'm happy that you found the module and understood it. May you be a better patient zero than I have been.

I wonder whether The Drupal version or The Wordpress Version will be the first to reach 1.000 active installations.

🇩🇰Denmark Steven Snedker

All assignations and credits are fine now.

Doing good work definitely scratches an itch.

🇩🇰Denmark Steven Snedker

Credits granted . When exiting a casino, pockets lined with credits, you usually exchange the credits for something valuable in the outside world (usually money). Where can I use my woefully incomplete molehill of credits ?

🇩🇰Denmark Steven Snedker

1.2.2: Added links to the Wayback Filter settings page. Added a "Nice to know" section. Should be available now .

The official Wayback Filter song is, of course, Take Me Back by Van Morrisson.

Take me way, way, way, way, way, way, way back (Ha)
Help me un— help me understand
Take me, do you remember the time darlin'
When everything made more sense in the world? (Yeah)
Oh, I remember, I remember when life made more sense

The Wayback Filter might take the user back to a time when links were not broken.

🇩🇰Denmark Steven Snedker

It's a great feature, and it's by design. Wayback Filter asks for a specific archived version based on the node's created date (sensible). Archive.org serves up the best match (sensible). We are all overcome by gratitude.

I have added a "Nice to know"-section to the settings page of the module and a "I don't get exactly the archived version I want"-paragraph to the module page .

You're the first to ask this question in 12 years. Nice to finally detect some interest. I wonder how fast the Wordpress lot will react.

🇩🇰Denmark Steven Snedker

@anaconda777 at my D11 site it opens the view /admin/structure/views/view/media_library/edit/page 

Post questions and feature requests at  https://www.drupal.org/project/issues/drupal?text=&status=Open&prioritie...

They will probably not answer questions like "In my Drupal 10 site there is a dropzone js, and max image upload size is 2mb. How can I change this?". But rest assured that ChatGPT, Perplexity and a host of other helpers will guide you expertly to your answer. Much better than Google.

This is a discussion of a single documentation page and, as such, very unlikely to solve your troubles.

🇩🇰Denmark Steven Snedker

Added an example of saving just the date (and not the time) to a field in a user.

🇩🇰Denmark Steven Snedker

@bisonbleau your addition to the Datetime overview documentation was a good one (and immediately accepted). You inspired me to elaborate further . I hope it'll help someone at some point.

🇩🇰Denmark Steven Snedker

Added a simple date formatting example with some advanced explaining.

🇩🇰Denmark Steven Snedker

You are absolutely right, @vegardjo. I've posted a better description for the og:image field as a feature request at More helpful description for the og:image field More helpful description for the og:image field Active .

🇩🇰Denmark Steven Snedker

I had the error. I corrected it.

In /simpleads/js/simpleads.charts.js

It says

function getLineChartOptions(xAxesLabel, yAxesLabel) {
    return {
      type: 'line',
      data: {
        labels: [],
        datasets: []
      },
      options: {
        responsive: true,
        tooltips: {
          mode: 'index',
          intersect: false,
        },
        hover: {
          mode: 'nearest',
          intersect: true
        },
        scales: {
          xAxes: [{
            display: true,
            scaleLabel: {
              display: true,
              labelString: xAxesLabel
            }
          }],
          yAxes: [{
            display: true,
            scaleLabel: {
              display: true,
              labelString: yAxesLabel
            }
          }]
        }
      }
    };
  };

Guided by the Chart-js 3.x migration docs, I changed it to

function getLineChartOptions(xAxesLabel, yAxesLabel) {
    return {
        type: 'line',
        data: {
            labels: [],
            datasets: []
        },
        options: {
            responsive: true,
            plugins: {
                tooltip: {
                    mode: 'index',
                    intersect: false
                }
            },
            hover: {
                mode: 'nearest',
                intersect: true
            },
            scales: {
                x: {
                    display: true,
                    title: {
                        display: true,
                        text: xAxesLabel
                    }
                },
                y: {
                    display: true,
                    title: {
                        display: true,
                        text: yAxesLabel
                    }
                }
            }
        }
    };
}

and it worked.

It should probably be further updated, but doing this, I got rid of the js errors.

🇩🇰Denmark Steven Snedker

@niranjan_panem the patch in #10 is probably better than nothing, but a long term useful solution.

Before patching:
Ask for "raw output" at Format - Fields - Config. This will give you a timestamp, no HTML.

After patching:
Ask or Custom: U at Date Format. This will give you a timestamp, no HTML.

What we need is
The correct solution:
Configuring the field, you should be able to set Formatter as "raw/no html markup"
Default/Time Ago just doesn't cut it as formatting options.

🇩🇰Denmark Steven Snedker

First constructive comments:

I suggested

Include most of the documentation (100+ lines?) on the module page. It's a great place for documentation! People will probably be more likely to install it, if they get the full picture up front.

Are you going to do that when the documentation is improved?

2. Did you consider talking about risk instead of chance?
ChatGPT did!

I prefer:
"Reducing technical debt and risk of vendor lock-in."

The word "risk" aligns better with "vendor lock-in," as it conveys the potential for a negative outcome more clearly than "chance," which can sound neutral or even positive.

I think ChatGPT is right here. What do you think?

I know it's a very small and not terribly significant bit of the documentation. But improving the documentation (and learning a bit doing it) is way faster than arguing about the need to improve it. It's also preferable to not improving it.

3. I still think

Requirements and Installation boilerplate should be removed. This is definitely not the first module a novice Drupal user will choose to install. Spend your time on the important details.

This time I might even venture that the boilerplate does more harm than good.

What do you think?

4. I still think you should be specific as to which settings.php file the users should seek out. What do you think?

As for the Configuration bit:

For example: 'local-example://filename.txt'.

should not be partially clickable.

The 'driver' key, is the type of adapter
'driver' => 'local', // The plugin key.

Driver, adapter, plugin. It's getting confusing. Too many different words.

These days I just think the main module should give up providing a useful, working example.

Farm the job out to the people who can, and link to them.

You'll save quite a bit of work and the users will save quite some time and frustration.

Suggestion for the Configuration bit:

Flysystem will not work unless you add arrays to your settings.php file (usually found at /sites/default/settings.php)

The maintainers of the flysystem submodules will tell exactly what they should look like.

Have a look at [insert the list of submodules/adapters]

These are currently the best and most useful examples
https://www.drupal.org/project/flysystem_dropbox
https://www.drupal.org/project/flysystem_gcs
https://www.drupal.org/project/flysystem_aliyun_oss

Why? You'll spot the examples immediately, and they work.

Spend some time telling the maintainers of the submodules to
a) upgrade to D11 and
b) provide examples starting with
$settings['flysystem'][s3'] = ...
$settings['flysystem']['dropbox'] = ...
$settings['flysystem']['cloud-storage'] = ...
...

(because $schemes = ... ; $settings['flysystem'] = $schemes; is not adequately copy&paste friendly).

c) Turn the adapters local and ftp into submodules like the ones above.

Then it'll be way easier to install Flysystem and her submodules.

🇩🇰Denmark Steven Snedker

@rudolfbyker has correctly identified a bug that should be squashed.

When exporting your nodes as json, you'd probably want to be able to easily export your dates in some easily machine-readable format.

For a project I'm currently working on
05.12.2024 - 17:11
is WAY superior to
<time datetime="2024-12-05T17:11:05+01:00">05.12.2024 - 17:11</time>\n

Silly workaround that works for me, but should only be temporary:
In the view, configuring the date fields: rewrite the result. Remove HTML tags and trim it to 18 characters (no ellipsis).

Another workaround:
Ask for "raw output" at Format - Fields - Config.
This will give you a timestamp, no HTML.

The correct solution:
Configuring the field, you should be able to set Formatter as "raw/no html markup"

🇩🇰Denmark Steven Snedker

As per #19 Add a helper function: drupal_get_now() Active and #20 Add a helper function: drupal_get_now() Active I give up.
I will not spend any more time trying to port this enhancement correctly to Drupal core. It's just not worth the effort.
May all your potential upcoming rewriting, pushing and requesting be met with success, @sourav_paul and @shalini_jha.

🇩🇰Denmark Steven Snedker

Added a crucial tip: remember to check "Allow the user to override the default view mode" in the text format.

🇩🇰Denmark Steven Snedker

Yes. We should do our utmost to help the users using our modules.

Migrate Wizard is probably a great module. But the documentation (I think it was mostly the documentation, but cannot be completely sure) made me opt for another solution.

🇩🇰Denmark Steven Snedker

@chi, your concers addressed

The implementation is hardcoded to one specific date format (Y-m-d\TH:i:s).

Yeah. It looks shoddy but
a) There is no core time format just like this
b) That is the time format that all datetime fields expect.

Can you improve it?

It overlaps with PSR 20 where now() is supposed to return DateTimeImmutable object.

Let's call this useful function getNow then.

It does not use core time service. So no way to mock the date in tests.

Hm. Is that a necessity?
Can you point to (or have ChatGPT create) the specific tests @smustgrave wishes for?

🇩🇰Denmark Steven Snedker

I'm so sorry for
a) Not seeing this until now
b) Making such a shoddy error message

The utf8mb4 check in the install file has now been vastly improved.

Is it still useful?
My guess is that 99% of people running Drupal 10, 11 do it on a database using utf8mb4.

Yet, I made a utf8mb4 check in the install file in order to save the few poor souls not using utf8mb4 from a White Screen of Death upon installation.

Phpstan should not choke on version 1.2.1. My apologies for the old, shoddy version.

🇩🇰Denmark Steven Snedker

You may want to make

drush ms
drush mim id_migration

part of the documentation for the module.

A chapter called "Running the migrations" in the README.md would be well received, I think.

🇩🇰Denmark Steven Snedker

I hear you, brother @sourav_paul. So I asked Claude to do it:

I'll create a PHPUnit test for this static method from the DrupalDateTime class.

This test class provides comprehensive coverage for the now() method with several test cases:

testNowDefaultFormat(): Tests the default ISO 8601 format and verifies the timestamp is current
testNowCustomFormat(): Tests various custom format strings using a data provider
testNowTimezone(): Verifies that the method always uses UTC regardless of system timezone

Key features of the tests:

  • Uses PHPUnit's data provider pattern to test multiple format strings
  • Includes regex pattern validation for different date formats
  • Handles timezone testing safely by restoring the original timezone
  • Includes proper PHPDoc blocks and type hints
  • Follows Drupal coding standards and testing conventions

You can run these tests using PHPUnit from your Drupal root directory:
./vendor/bin/phpunit core/tests/Drupal/Tests/Core/Datetime/DrupalDateTimeTest.php

And here's the test. I hope you can suss out where to put it:

<?php

namespace Drupal\Tests\Core\Datetime;

use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Tests\UnitTestCase;

/**
 * @coversDefaultClass \Drupal\Core\Datetime\DrupalDateTime
 * @group DateTime
 */
class DrupalDateTimeTest extends UnitTestCase {

  /**
   * Tests the default format of the now() method.
   *
   * @covers ::now
   */
  public function testNowDefaultFormat(): void {
    $datetime = DrupalDateTime::now();
    
    // Validate the format matches ISO 8601
    $this->assertMatchesRegularExpression(
      '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/',
      $datetime,
      'Default format should match ISO 8601 format (Y-m-d\TH:i:s)'
    );
    
    // Validate the timestamp is within 1 second of current time
    $now = time();
    $test_time = strtotime($datetime);
    $this->assertLessThanOrEqual(1, abs($now - $test_time), 
      'Generated timestamp should be within 1 second of current time'
    );
  }

  /**
   * Tests the now() method with custom formats.
   *
   * @covers ::now
   * @dataProvider provideTimeFormats
   */
  public function testNowCustomFormat(string $format, string $pattern): void {
    $datetime = DrupalDateTime::now($format);
    
    $this->assertMatchesRegularExpression(
      $pattern,
      $datetime,
      sprintf('Format %s should match pattern %s', $format, $pattern)
    );
  }

  /**
   * Data provider for testNowCustomFormat.
   *
   * @return array
   *   Test cases with format strings and their corresponding regex patterns.
   */
  public function provideTimeFormats(): array {
    return [
      'Year only' => [
        'Y',
        '/^\d{4}$/',
      ],
      'Date only' => [
        'Y-m-d',
        '/^\d{4}-\d{2}-\d{2}$/',
      ],
      'Time only' => [
        'H:i:s',
        '/^\d{2}:\d{2}:\d{2}$/',
      ],
      'Custom format' => [
        'd/m/Y H:i',
        '/^\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}$/',
      ],
      'Unix timestamp' => [
        'U',
        '/^\d+$/',
      ],
    ];
  }

  /**
   * Tests that the now() method uses UTC timezone.
   *
   * @covers ::now
   */
  public function testNowTimezone(): void {
    // Store current timezone
    $current_timezone = date_default_timezone_get();
    
    try {
      // Set system timezone to something other than UTC
      date_default_timezone_set('America/New_York');
      
      // Get timestamp in both timezones
      $utc_time = strtotime(DrupalDateTime::now('Y-m-d H:i:s'));
      $ny_time = strtotime((new \DateTime('now', new \DateTimeZone('America/New_York')))->format('Y-m-d H:i:s'));
      
      // Calculate the offset (should be 4 or 5 hours depending on daylight savings)
      $offset = abs($ny_time - $utc_time);
      
      $this->assertTrue(
        $offset >= 14400 && $offset <= 18000,
        'UTC time should differ from New York time by 4-5 hours'
      );
    }
    finally {
      // Restore original timezone
      date_default_timezone_set($current_timezone);
    }
  }

}
🇩🇰Denmark Steven Snedker

That's a rejection then.

I accept that.

My guess is, that you'll gradually change your mind on the "Modules should work AND be solely written by a person".

Not much skin off my back.

Here's the breakdown from my work log:
1 hour: have Claude make a very useful module and test it
1 hour: try to get better and more obvious maintainers to make or adopt it.
2 hours: security applications and related discussions.
6 hours: make (to us: very limited value) phpcs, phpcbd work company wide.
2 hours: git work

Disregarding the community is by far the path of least resistance.

Making your own great modules locally may be the future for Drupal.

🇩🇰Denmark Steven Snedker

@vishal.kadam: It was a one-minute job with Claude "Turn this into a correctly formatted Drupal module README.md file, render it as markdown: [readme.txt]". And it just works.

@avpaderno I too had my doubts about modules written by AI. So I asked an adult for guidance.

She said (paraphrased): If it works and isn't riddled with back doors, go for it. I see a bright future for Drupal with more and better features made significantly faster than in the old days.

So.

Does it work? Yes.

Is it riddled with back doors? No.

I have it running in production.

I vouch for the quality. But that's not very interesting yet, as I'm a small fry in the middle of a Drupal.org security advisory coverage application. Although, I have been publishing working modules on Drupal.org since 2006 . I will admit to possessing an adequate amount of Drupal knowledge.

Smart programmers will use Drush, IDE extensions and LLMs to get the work done fast and well.

🇩🇰Denmark Steven Snedker

Looks very fine to me. Short, elegant and to the point.

Sadly I have no idea why we get "Merge request pipeline #339722 failed" at PHPUnit Functional 7/8 or how to get out of this regrettable situation.

🇩🇰Denmark Steven Snedker

Well, my preference is

  1. drupal_get_now() (global function, not the modern Drupal way, will probably not make it into core)
  2. \Drupal\Core\Datetime\DrupalDateTime::now() (You'll almost be able to remember this one)
  3. \Drupal::service('datetime.service')->now() (harder to remember)

Naming
now is short and easy to remember. It's not as distinct as getNowUTC, but your IDE would probably tell you that now returned the date+time as UTC.

Make a patch @nikhil_110 and set the ball in motion!

🇩🇰Denmark Steven Snedker

I had Claude make the great Entityqueue Buttons module. You can find it at https://vertikal.dk/entityqueue_buttons.zip.

My hope is that @amateescu, @quicksketch or @jojonaloha will try it out and make it a submodule of Entityqueue. Or maybe publish it as a distinct project and link to it from the Entityqueue project page.

What makes the Entityqueue Buttons module useful? You only have to click once to add or remove a node. It'll also cut down on the confusion a very junior editor may feel.

Drawbacks? You'll get an add/remove button on your nodes, that only editors can see. Shouldn't be that ugly or confusing.

🇩🇰Denmark Steven Snedker

Claude is pretty keen on the idea:

That's a great idea to simplify this common operation! Let me think through the architectural considerations:

Public static method vs. global function:

  • Given Drupal's move away from global functions, a static method would indeed be more aligned with modern best practices
  • It would maintain better encapsulation and namespace organization
  • It follows object-oriented principles better than adding to the global namespace
  • It makes the functionality more discoverable through IDE tooling

A static method could look something like:

public static function nowUtc(string $format = 'Y-m-d\TH:i:s'): string 
{
    return (new static('now', new \DateTimeZone('UTC')))->format($format);
}

Then you could use it as:

$now = \Drupal\Core\Datetime\DrupalDateTime::nowUtc();

This gives you:

  • A cleaner, more maintainable API
  • The ability to easily extend with additional formats or timezones if needed
  • Better consistency with modern PHP practices
  • Clear indication that this is Drupal-specific datetime functionality

Would you like me to explore other potential approaches or elaborate on any aspects of this solution?

Trading
$now = (new \Drupal\Core\Datetime\DrupalDateTime('now', new \DateTimeZone('UTC')))->format('Y-m-d\TH:i:s');
for
$now = \Drupal\Core\Datetime\DrupalDateTime::nowUtc();
is slightly better. You do not have to remember hyperspecific stuff like 'Y-m-d\TH:i:s'.

Having it as a better service

# Create a new service class
class DateTimeService {
  public function getNowUtc(string $format = 'Y-m-d\TH:i:s'): string {
    return (new DrupalDateTime('now', new \DateTimeZone('UTC')))->format($format);
  }
}

would also trade very specific and human-unfriendly
$now = \Drupal::service('date.formatter')->format(time(), 'custom', 'Y-m-d\TH:i:s', 'UTC');
for better
$now = \Drupal::service('datetime.service')->getNowUtc();

I'm not sure if which of the public static function or the service will play nicest with IDE tooling. Which one would require the least remembering aand typing?

My VS Code, filled to the brim with the right extensions still makes me pine for simple, global functions.

$user = user_load(42);
is still way easier than
$user = \Drupal::entityTypeManager()->getStorage('user')->load(42);

🇩🇰Denmark Steven Snedker

Forgot to add 3600 to $an_hour_later.

🇩🇰Denmark Steven Snedker

Added a paragraph about saving datetimes, dateranges and timestamps programmatically. Updated the tags.

🇩🇰Denmark Steven Snedker

Cool! I look forward to trying it.

Are you on track to having the high priests bestow a vetted role upon you ? (Sadly, I'm not).

That would give the module the coveted "Stable releases for this project are covered by the security advisory policy.
Look for the shield icon below." badge.
(Which my modules on Drupal.org has - but only because they've been grandfathered into the security coverage.)

🇩🇰Denmark Steven Snedker

The generic description is very brief and does mention Buzzsprout in passing:

Configuration & Use
Install this module as usual.
Create a new Media Type, select "Remote Media URL" as Media source
Important: Configure the display, selecting as formatter in the URL field your desired provider. For example, if you are creating a "Buzzsprout" media type, select "Remote Media - Buzzsprout" as formatter for the URL field in the "Manage display" tab.

My proposed resolution is guaranteed to show newbies the ropes by
a) providing them with an actual working example (that's Drupal Module Gold)
b) taking them through all 7 steps in the correct sequence.

The smart ones can probably write something other than Buzzsprout on their first run. The less smart ones can get a working example and change bits and pieces until it works with another provider. Or make a new one in the vein of Buzzsprout.

A generic Configuration & Use where Buzzsprout is changed to [PROVIDERNAME] and [PROVIDERURL] is less readable. And won't necessarily work.

I also like the bit in step 6:

Click "Add" (clicking "Save" will make stuff explode). Click "Save". Click "Insert selected". (Scroll to the bottom and) click "Save".

It's probably still correct (but I haven't tested since June, so who knows).

My conclusion: this patch is useful for everyone and a great improvement.

🇩🇰Denmark Steven Snedker

I'm very impressed with the solution in #14. Repaired the upcoming version of Wayback Filter as well. Thank you, Julien.

🇩🇰Denmark Steven Snedker

"If you want to use a different font you can just load them via CSS?"
Perhaps. In the example, I use the Oliviero theme and use the cwl custom module to alter/replace the entity-print.css.

It's a rather complicated way of doing things, I admit. But I found no simpler module-centric way that actually worked IRL.

I seemingly had to follow all these very complicated steps to have cwl-print.css load at the right time and actually work.

As for storing fonts locally, it's just a GDPR thing.

Thank you. Matt B, for your efforts regarding better documentation.

🇩🇰Denmark Steven Snedker

Needed additional formatting

🇩🇰Denmark Steven Snedker

It took quite a few steps to route around entity-print.css and use my own module supplied css. I gifted this actually working example to the newbies. 

🇩🇰Denmark Steven Snedker

I'd love to write a patch, but as you can see I'm not sufficiently fluent in English, I have no useful git.drupalcode.org access and I can't even target the correct version of the splendid Flysystem module. Also I have only an hours experience with the module.

Looking at the flysystem 2.2.x-dev DEV readme I can see I would have missed quite a few important points. I'd say people were better off if the Flysystem module page linked to the flysystem 2.2.x-dev DEV readme instead of the faulty/less stellar 8.x-1.x readme.

I'm also happy that useful documentation is now a task and not a bug.

I was misled by this ChatGPT answer:

Is faulty documentation of a Drupal module a bug?

Yes, faulty documentation of a Drupal module can be considered a bug. Documentation is an integral part of software development, as it helps users understand how to use the module correctly. If the documentation is incorrect, incomplete, or misleading, it can cause users to misuse the module or struggle to implement it effectively. This can be as disruptive as a functional bug in the code itself. Therefore, reporting and addressing documentation issues is crucial for maintaining the overall quality and usability of the module.

Thank you for improving he Flysystem module - and the documentation!

🇩🇰Denmark Steven Snedker

Having the video(url) show up in the media library added no benefits to my project, I found.

So I ended up with a simpler solution than installing, patching, tweaking and setting up the Media Remote module:

function mymodule_preprocess_node(&$variables) {
  if (!empty($variables['node']->get('field_video')->value)) {
    $video_link = $variables['node']->get('field_video')->value;
    $variables['content']['field_video'] = [
      '#type' => 'inline_template',
      '#title' => 'Video',
      '#template' => '<video controls><source src="{{ url }}" type="video/mp4"></video>',
      '#context' => ['url' => $video_link],
    ];
}

If you have a text field called video in a node, and you type in a remote video url, when editing the node, a video player will appear when viewing the node, instead of the text.

Video urls should be https://. Otherwise your browser might not play the video and might give you a strange error message

I hope someone will save some hours.

🇩🇰Denmark Steven Snedker

Thank you!

I can confirm it works with a short URL like https://vertikal.dk/sites/default/files/keys.mp4

On URLs longer than 245 chars it breaks. Because the name of the video is supposed to fit in 255 chars.

In the MediaRemoteVideoFormatter.php I changed

public static function deriveMediaDefaultNameFromUrl($url) {
    $pattern = static::getUrlRegexPattern();
    if (preg_match($pattern, $url)) {
      return t('Video from @url', [
        '@url' => $url,
      ]);
    }
    return parent::deriveMediaDefaultNameFromUrl($url);
  }

to

public static function deriveMediaDefaultNameFromUrl($url) {
    $pattern = static::getUrlRegexPattern();
    if (preg_match($pattern, $url)) {
      return t('Video from @url', [
        '@url' => substr($url, 0, 200),
      ]);
    }
    return parent::deriveMediaDefaultNameFromUrl($url);
  }

to make it work.

I also had to relax getUrlRegexPattern() in order to make videos like
http://mywonderfulNAS.myds.me:8764/share.cgi/Homevideo%20U-Matic/1061.mp...
almost work.

In the MediaRemoteVideoFormatter.php I changed

public static function getUrlRegexPattern() {
    return '/^https?.*?\.mp4/';
  }

to

public static function getUrlRegexPattern() {
    return '/^http?.*/';
  }

The player is still adamant that "No video with supported format and MIME type found" - but this is probably not related to this module or this formatter.

At least the player will get the correct url this way.

🇩🇰Denmark Steven Snedker

The current documentation is clearly inadequate. It has not been updated for four years.

I wish I could update it on https://git.drupalcode.org, but I'm not allowed to neither edit nor fork over there.

So here's an error ridden, but hopefully useful, stab at some better documentation:

1. The Flysystem module page links to
http://cgit.drupalcode.org/flysystem/plain/README.md?h=8.x-1.x
This page look pretty ugly in a browser. Link to
https://git.drupalcode.org/project/flysystem/-/blob/2.0.x/README.md?ref_...
or some such instead.

Better yet. Include most of the documentation (100+ lines?) on the module page. It's a great place for documentation! People will probably be more likely to install it, if they get the full picture up front.

2. "Reducing technical debt and risk of vendor lock-in." is slightly better than the current "Reducing technical debt and chance of vendor lock-in."

3. Requirements and Installation boilerplate should be removed. This is definitely not the first module a novice Drupal user will choose to install. Spend your time on the important details.

4. "Stream wrappers are configured in settings.php (usually found in /sites/default/settings.php or /web/sites/default/settings.php".
There are two settings.php in a typical D10 installation (the other one is at /core/lib/Drupal/Core/Site). And nearly 20 *settings.php files. We'd hate to confuse people.

5. Troubleshooting. Fine. But place it after the Configuration bit, where people need it.

6. Configuration. The example does not work.

This example will work

$schemes = [
  'local-example' => [ // The name of the stream wrapper.

    'driver' => 'local', // The plugin key.

    'config' => [
      'root' => '/../../', // Path to directory outside Drupal. Maybe /var/www/html/storage or ../ works better, who knows? 'sites/default/files/flysystem' would be a part of the public file system.
      'public' => TRUE, // In order for the public setting to work,
      // the path must be relative to the root
      // of the Drupal install.

      // Optional settings that apply to all adapters.

      'name' => 'local-example', // Optional. Defaults to something secret.
      'description' => 'An example of a local flyssystem file system',  // // Optional. Defaults to something secret.

      'cache' => TRUE, // Cache filesystem metadata. Not necessary for
      // the local driver.

      'replicate' => 'ftp-example', // 'replicate' writes to both filesystems, but
      // reads from this one. Functions as a backup.

      'serve_js' => TRUE, // Serve Javascript or CSS via this stream wrapper.
      'serve_css' => TRUE, // This is useful for adapters that function as
      // CDNs like the S3 adapter.
    ],
  ],

    'ftp-example' => [
      'driver' => 'ftp',
      'config' => [
        'host' => 'ftp.storaro.it', // or whatever the name of your ftp host is
        'username' => 'storaro', // use a better username
        'password' => 'cin3matograph3r', // use a better password

        // Optional config settings.
        'port' => 21,
        'root' => '/var/www/html/storage',
        'passive' => true,
        'ssl' => false,
        'timeout' => 90,
        'permPrivate' => 0700,
        'permPublic' => 0700,
        'transferMode' => FTP_BINARY,
      ],
    ],
];

// Don't forget this!
$settings['flysystem'] = $schemes;

6) Troubleshooting. Have a look at the status report (admin/reports/status) to see if it works.
And on the status page, you should never write "ftp returned an error". That's close to useless. What error did it return? Should the user have a closer look at the hostname, port, username or password?

7) How to use the module.
"Now whenever you add a NEW file field to a node type/entiity type, you can decide which file system to use. You cannot change the file system for existing fields, though. Only new fields get the benefit of the module.

🇩🇰Denmark Steven Snedker

I, too, made a small module to mitigate this error. Back Button Disable Module .
I won't upload it as a proper Drupal module. Drupal 7 is soon end of life and uploading modules to drupal.org is a time-consuming chore.

🇩🇰Denmark Steven Snedker

I, too, made a small module to mitigate this error. Back Button Disable Module .
I won't upload it as a proper Drupal module. Drupal 7 is soon end of life and uploading modules to drupal.org is a hideous and time-consuming chore.

Production build 0.71.5 2024