[Iltalehti] IltaPlus

Iltalehden "Plus-Tilaus" ilmaiseksi

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        [Iltalehti] IltaPlus
// @namespace   HKR
// @match       https://www.iltalehti.fi/*
// @grant       none
// @version     2.2
// @author      HKR
// @description Iltalehden "Plus-Tilaus" ilmaiseksi
// @run-at      document-load
// @grant       GM_addStyle
// ==/UserScript==

class ElementGenerator {
    handleType(type, sectionData) {
        switch(type) {
            case "paragraph":
                return this.paragraph(sectionData.items);
            case "subheadline":
                return this.subheadline(sectionData.text);
            case "list":
                return this.list(sectionData.items);
            case "aside":
                return this.aside(sectionData.items);
            case "related-article":
                return this.relatedArticle(sectionData.article);
            case "image":
                return this.image(sectionData);
            case "directImage":
                return this.directImage(sectionData);
            case "embed":
                return this.embed.unknown(sectionData);
            case "divider":
                return this.divider();
        }
    }

    content(contentArr) {
        let generatedHTML = "";

        contentArr.forEach(item => {
            const type = item.type;

            switch(type) {
                case "text":
                    generatedHTML += `${item.text}`;
                    break;

                case "bold":
                    let boldText = "";

                    item.items.forEach(boldItem => {
                        boldText += boldItem.text;
                    });

                    generatedHTML += `<strong>${boldText}</strong>`;
                    break;

                case "link":
                    let generatedContent = this.content(item.items);

                    generatedHTML += `<a href="${item.url}">${generatedContent}</a>`;
                    break;

                case "italic":
                    let italicText = "";

                    item.items.forEach(item => {
                        italicText += item.text;
                    });

                    generatedHTML += `<i>${italicText}</i>`;
                    break;

                default:
                    let text= "";

                    item.items.forEach(item => {
                        text += item.text;
                    });

                    generatedHTML += text;
                    break;
            }
        });

        return generatedHTML;
    }

    paragraph(contentArr) {
        let paragraph = document.createElement('p');
        paragraph.className = "paragraph";

        let generatedHTML = this.content(contentArr);

        paragraph.innerHTML = generatedHTML;

        return paragraph;
    }

    subheadline(textContent) {
        const subheadline = document.createElement('h3');
        subheadline.className = "subheadline";
        subheadline.innerText = textContent;

        return subheadline;
    }

    image(imageData) {
        const image = document.createElement('div');
        image.className = `article-image gallery ${imageData.properties.float}`;
        image.setAttribute("itemprop", "image");
        image.setAttribute("itemscope", "");
        image.setAttribute("itemtype", "http://schema.org/ImageObject");
        image.setAttribute("role", "button");
        image.setAttribute("tabindex", "0");
        image.innerHTML = `
        <div class="article-image-container" style="padding-bottom:${(imageData.properties.height / imageData.properties.width) * 100}%">
            <img class="image image-show image-preview" src="${imageData.urls.size30}" alt="${imageData.properties.caption}">
            <img class="image image-show" src="${imageData.urls.size612}" srcset="${imageData.urls.size310} 310w, ${imageData.urls.size510} 510w, ${imageData.urls.size612} 612w" alt="${imageData.properties.caption}">
        </div>
        <meta itemprop="url" content="${imageData.urls.size612}">
        <meta itemprop="width" content="${imageData.properties.width}">
        <meta itemprop="height" content="${imageData.properties.height}">
        <div class="media-caption">
            <meta itemprop="description" content="${imageData.properties.caption}"/>
            <span class="caption-text" itemprop="description">${imageData.properties.caption}</span>
            <span class="media-source">${imageData.properties.source}</span>
        </div>
        `;

        return image;
    }

    directImage(imageData) {
        const image = document.createElement('div');
        image.className = `article-image gallery ${imageData.float}`;
        image.setAttribute("itemprop", "image");
        image.setAttribute("itemscope", "");
        image.setAttribute("itemtype", "http://schema.org/ImageObject");
        image.setAttribute("role", "button");
        image.setAttribute("tabindex", "0");
        image.innerHTML = `
        <div class="article-image-container" style="padding-bottom:${(imageData.height / imageData.width) * 100}%">
            <img class="image image-show image-preview" src="${imageData.urls.size30}" alt="${imageData.caption}">
            <img class="image image-show" src="${imageData.urls.size612}" srcset="${imageData.urls.size310} 310w, ${imageData.urls.size510} 510w, ${imageData.urls.size612} 612w" alt="${imageData.caption}">
        </div>
        <meta itemprop="url" content="${imageData.urls.size612}">
        <meta itemprop="width" content="${imageData.width}">
        <meta itemprop="height" content="${imageData.height}">
        <div class="media-caption">
            <meta itemprop="description" content="${imageData.caption}"/>
            <span class="caption-text" itemprop="description">${imageData.caption}</span>
            <span class="media-source">${imageData.source}</span>
        </div>
        `;

        return image;
    }

    list(items) {
        const listElem = document.createElement('div');
        listElem.className = "article-bullets";

        const list = document.createElement('ul');

        items.forEach(item => {
            let generatedHTML = this.content(item);

            list.innerHTML += `<li>${generatedHTML}</li>`;
        });

        listElem.appendChild(list);

        return listElem;
    }

    aside(items) {
        const asideContainer = document.createElement('div');
        asideContainer.className = "aside-container";

        const aside = document.createElement('div');
        aside.className = "aside";

        items.forEach(item => {
            const type = item.type;

            const sectionElement = this.handleType(type, item);

            if(typeof sectionElement == "object") {
                aside.appendChild(sectionElement);
            }
        });

        asideContainer.appendChild(aside);

        return asideContainer;
    }

    relatedArticle(article) {
        const relatedArticle = document.createElement('div');
        relatedArticle.className = "related-articles related-articles-within-text";

        relatedArticle.innerHTML += `<h3>Lue myös</h3>`;
        relatedArticle.innerHTML += `<a href="/${article.category.category_name}/a/${article.article_id}">${article.headline}</a>`;

        return relatedArticle;
    }

    divider() {
        const divider = document.createElement('div');
        divider.className = "article-divider";
        divider.innerHTML = `<div class="article-divider-content"></div>`;

        return divider;
    }

    embed = {
        twitter: twitterData => {
            const twitterEmbed = document.createElement('div');
            twitterEmbed.className = "twitter-container article-embed";
            twitterEmbed.innerHTML = twitterData.embed_html;

            return twitterEmbed;
        },
        default: embedData => {
            const embed = document.createElement('div');
            embed.innerHTML = embedData.embed_html;

            return embed.firstChild;
        },
        unknown: embedData => {
            switch(embedData.name) {
                case "twitter": return this.embed.twitter(embedData);
                default: return this.embed.default(embedData);
            }
        }
    }
};

const bypassPaywall = async () => {
    const page = digitalData.page.attributes;
    const pageID = page.content.cid;
    const paidArticle = page.contentCharge == "paid" ? true : false;

    if(!paidArticle) return; // article is free, do not proceed

    const articleBodyElement = document.createElement('div');
    articleBodyElement.id = "bypassed-article-body";
    articleBodyElement.innerHTML = `
    <div style="margin-bottom: 10px;">
        <a class="subheadline" href="https://github.com/Hakorr/Userscripts/tree/main/Iltalehti.fi/IltaPlus">
            Bypassed by <strong>IltaPlus</strong>
        </a>
    </div>
    `;

    const articleData = await fetch(`https://api.il.fi/v1/articles/${pageID}?include_main_media=true`)
        .then(response => response.json())
        .then(json => json.response);

    console.log("Article data: ", articleData);

    const articleBody = articleData.body;
    const articleImages = articleData.ímages;

    const ElemGen = new ElementGenerator();

    articleBody.forEach(sectionData => {
        const type = sectionData.type;

        const sectionElement = ElemGen.handleType(type, sectionData);

        if(typeof sectionElement == "object") {
            articleBodyElement.appendChild(sectionElement);
        }
    });

    articleData?.["images"].forEach(sectionData => {
        const sectionElement = ElemGen.handleType("directImage", sectionData);

        if(typeof sectionElement == "object") {
            articleBodyElement.appendChild(sectionElement);
        }
    });

    GM_addStyle(`
    .subheadline {
         font-size: 18px; margin: 0 14px 15px;
    }
    .aside-container {
        clear: both;
        font-size: 16px;
        margin: 0 14px 14px;
        border: 1px solid #ddd;
    }
    .aside-container h3:first-of-type {
        margin: 14px;
    }
    .aside-container h3 {
        font-family: Bernino Sans Condensed,Arial,Verdana;
        font-size: 16px;
        font-weight: 700;
        margin: 10px 14px;
    }
    .paragraph {
        margin: 0 14px 15px;
        line-height: 1.45;
    }
    .media-source {
      opacity: 0.5;
    }
    `);

    console.log("Processed (n' bypassed) article:", articleBodyElement);

    document.querySelector(".article-body").innerHTML = articleBodyElement.innerHTML;
    document.querySelector("#anop-container")?.remove();
};

let lastID = "";

setInterval(() => {
    let currentID = digitalData.page.attributes.content.cid;

    if(lastID != currentID)
    {
        lastID = currentID;
        bypassPaywall();
    }
}, 500);