[Iltalehti] IltaPlus

Iltalehden "Plus-Tilaus" ilmaiseksi

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==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);