Pay-Per-View Content Contract

What it does:
Allows creators to sell access to digital content (videos, articles, courses) on a pay-per-view basis, collecting revenue automatically on-chain.

Why it matters:
Eliminates intermediaries, ensures instant payments to creators, prevents unauthorized access, and tracks viewership transparently.

How it works:

  • Creators register content with metadata and a per-view price

  • Users pay the required fee on-chain to unlock access

  • Smart contract tracks which addresses have access to the content

  • Access can be time-limited or permanent per payment

  • Revenue is collected and optionally split among multiple stakeholders

  • Content access history is auditable and tamper-proof

  • Integrates easily with NFTs or subscription models for premium content

      // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title PayPerViewContent
 * @author Nam
 * @notice Sell digital content access on a pay-per-view basis
 */
contract PayPerViewContent {

    address public admin;
    uint256 public contentCount;

    struct Content {
        string metadataHash; // IPFS or encrypted content reference
        address payable creator;
        uint256 price; // in wei per view
        mapping(address => bool) viewers; // tracks who has access
    }

    mapping(uint256 => Content) public contents;

    // -------------------- EVENTS --------------------

    event ContentRegistered(uint256 indexed contentId, address indexed creator, uint256 price);
    event ContentPurchased(uint256 indexed contentId, address indexed viewer, uint256 amount);

    // -------------------- MODIFIERS --------------------

    modifier onlyAdmin() {
        require(msg.sender == admin, "Not admin");
        _;
    }

    // -------------------- CONSTRUCTOR --------------------

    constructor() {
        admin = msg.sender;
    }

    // -------------------- CONTENT MANAGEMENT --------------------

    function registerContent(string calldata _metadataHash, uint256 _price) external {
        require(_price > 0, "Price must be >0");

        contentCount += 1;
        Content storage c = contents[contentCount];
        c.metadataHash = _metadataHash;
        c.creator = payable(msg.sender);
        c.price = _price;

        emit ContentRegistered(contentCount, msg.sender, _price);
    }

    // -------------------- PAY-PER-VIEW ACCESS --------------------

    function purchaseContent(uint256 _contentId) external payable {
        Content storage c = contents[_contentId];
        require(msg.value == c.price, "Incorrect payment");
        require(!c.viewers[msg.sender], "Already purchased");

        c.viewers[msg.sender] = true;
        c.creator.transfer(msg.value);

        emit ContentPurchased(_contentId, msg.sender, msg.value);
    }

    function hasAccess(uint256 _contentId, address _user) external view returns (bool) {
        return contents[_contentId].viewers[_user];
    }
}