S3D Player: private video catalog on Cloudflare R2
==================================================

This package lets S3D Player users watch your 3D videos from Cloudflare R2
storage by user name and password. Your web hosting only checks passwords
and issues short signed links; the video itself goes from R2 directly to the
viewer, so large files take neither space nor traffic on your hosting.

Files
-----
  config.php   your settings (the only file you need to edit)
  list.php     video list for the player (login and password)
  get.php      checks a signed link and redirects to R2
  admin.php    admin panel: users and statistics (rename it, see step 5)
  common.php   common functions (internal)
  r2.php       Cloudflare R2 access (internal)
  hash.php     password hash from the console (optional)
  .htaccess    closes internal files from the web

Requirements
------------
  * Web hosting with Apache 2.4 (.htaccess enabled) and HTTPS
  * PHP 7.3 or newer with the cURL and SimpleXML extensions
  * A Cloudflare account with R2 enabled

Step 1. Create a bucket and upload videos
-----------------------------------------
In the Cloudflare dashboard open "R2 object storage" and create a bucket.
Upload your videos (mp4, mkv, avi, mov, m4v, m2ts, mts, ts, webm, wmv, mpg).
Subfolders are allowed.

The player detects the 3D format from the file name, so keep the usual
marks in the names, for example "Movie sbs.mp4" or "Movie_p.mkv".

Preview (optional): upload an image with the same name next to the video,
for example "Movie sbs.jpg" (jpg, png or webp). Without an image the player
takes a frame from the video. The frame time can be set with a text file
"Movie sbs.thumb" containing a number of seconds, or in config.php.

Step 2. Create a read only key
------------------------------
In "R2 object storage", section "Account Details", click "Manage" next to
"API Tokens" and create a token:
  Permissions: Object Read only
  Buckets:     Apply to specific buckets only, select your bucket
  TTL:         Forever
  Client IP Address Filtering: leave empty

After creation copy three values:
  Access Key ID
  Secret Access Key  (shown only once)
  the S3 endpoint    https://<ACCOUNT_ID>.r2.cloudflarestorage.com
The "Token value" line is not used by this package. Do not share it.

Step 3. Upload the package
--------------------------
Copy all files of this package into a folder on your hosting, for example
  https://example.com/cloudflare/
Make sure .htaccess is uploaded too (some FTP clients hide files starting
with a dot).

Step 4. Edit config.php
-----------------------
  S3D_R2_ENDPOINT           the S3 endpoint from step 2
  S3D_R2_ACCESS_KEY_ID      Access Key ID from step 2
  S3D_R2_SECRET_ACCESS_KEY  Secret Access Key from step 2
  S3D_R2_BUCKET             your bucket name
  S3D_R2_PREFIX             folder in the bucket ("movies/") or empty for all
  S3D_BASE_URL              https address of the package folder, no trailing "/"
  S3D_SECRET                your own random string of 40 or more letters and
                            digits (use a password generator). Keep it private.
  S3D_ADMIN_PASS            admin password for the first login
  S3D_ADMIN_FILE            admin page file name, see step 5

Leave the other values as they are.

Step 5. Admin panel
-------------------
Invent your own file name for the admin page, for example
"panel-7k2x.php" (letters, digits, "_" and "-", at least 6 characters).
Rename admin.php to this name and write the same name in S3D_ADMIN_FILE.
Under any other name, including admin.php, the page answers 404: this
hides it from people who scan sites for admin pages.

Open https://example.com/cloudflare/panel-7k2x.php and log in with
S3D_ADMIN_PASS. Then:
  * check the "Server check" block: the number of videos found in R2 and
    that the folders are writable. An R2 error (keys, endpoint, cURL) is
    shown right there
  * set a new admin password (section "Admin password")
  * add users with passwords; choose "view only" or "save allowed"
  * delete or disable the demo user "demo-user" (password 12345)

"access on/off" blocks a user at once, including links issued earlier.
The panel also shows all videos in the bucket, who watched and saved what,
and failed logins by IP.

Forgot the admin password: delete private/admin.json via FTP; the password
from S3D_ADMIN_PASS works again.

Step 6. Test the server
-----------------------
In the Windows command prompt (replace the address, user and password):

  curl -i -X POST -d "user=demo-user&pass=12345" "https://example.com/cloudflare/list.php"

  200 and "#private" on the first line   the server works
  403                                     wrong user or password, or not HTTPS
  429                                     too many wrong passwords, wait 15 min
  503 "#error storage unavailable"        see Troubleshooting below

Step 7. Add the catalog to S3D Player
-------------------------------------
In S3D Player open the Media Manager (Catalog button), click "User" and add:

  [My R2 videos]
  url      = https://example.com/cloudflare/list.php
  user     = demo-user
  password = 12345

Save the file, select the source and click "Rescan".
Optional: "save_dir = D:\Video\Saved" sets where saved videos go.

How it works
------------
  * list.php checks the password and returns the video list with links
    signed for this user, valid for 12 hours (S3D_LINK_SEC).
  * get.php checks the signature and redirects the player to a direct R2
    link valid for 10 minutes (S3D_R2_URL_SEC). No video data passes
    through PHP; seeking works directly with R2.
  * The R2 key never leaves your hosting.
  * New files in the bucket appear in the list within 60 seconds
    (S3D_CATALOG_CACHE_SEC).
  * "save allowed" only enables the Save option in the player. Anyone who
    can watch a video can technically record it; this is not DRM.

Service data
------------
The folder data/ (S3D_DATA) is created automatically and closed from the
web by its own .htaccess. It holds:
  access.log      log of logins, plays, saves and errors
  users.json      users (after the first change in the admin panel)
  catalog-*.json  catalog cache
  fail_*.txt      failed login counters
The folder private/ (created by the admin panel) holds the admin password
hash. Files are created with open permissions, so both folders can be
edited or deleted by FTP.

Troubleshooting
---------------
The exact reason of an error is written to data/access.log (line starting
with "ERROR") and shown in the admin panel, block "Last events".

  ERROR PHP cURL extension is required
      enable the PHP cURL extension in the hosting control panel
  ERROR Set the exact R2 S3 API endpoint in config.php
      S3D_R2_ENDPOINT must be exactly https://<ACCOUNT_ID>.r2.cloudflarestorage.com
  ERROR Set R2 Access Key ID and Secret Access Key in config.php
      the keys are still the REPLACE_ placeholders
  ERROR Set your own random S3D_SECRET ...
      S3D_SECRET is still the placeholder or shorter than 32 characters
  ERROR R2 returned HTTP 403 ...
      wrong keys, the token is not for this bucket, or the server clock is wrong
  ERROR R2 returned HTTP 404 ...
      wrong bucket name
  ERROR Cannot create S3D_DATA ...
      PHP cannot create the data/ folder: create it by FTP and allow writing

  Admin page answers 404
      the file name and S3D_ADMIN_FILE differ, or S3D_ADMIN_FILE is empty
  list.php answers 403 with the right password
      the site is opened by http, not https

Copyright (c) S3D Singapore 2026, https://gradient-sg.com
