Greasy Fork is available in English.

Whatsapp Wall

Whatsapp web media slide show!

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

Advertisement:

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

Advertisement:

作者のサイトでサポートを受ける。または、このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Whatsapp Wall
// @namespace    http://whatsappweb.com/whatsapp-wall
// @version      0.2.2
// @description  Whatsapp web media slide show!
// @author       Tom Van Rossom
// @match        https://web.whatsapp.com/
// @grant        none
// @supportURL   https://github.com/tomvanrossom/Whatsapp-Wall
// @require      https://code.jquery.com/jquery-2.1.4.min.js
// ==/UserScript==

( function( $ ) {
    const DEFAULT_INTERVAL = 5000;

    function addGlobalStyle( css ) {
        let head;
        let style;
        head = document.getElementsByTagName( 'head' )[ 0 ];
        if ( !head ) {
            return;
        }
        style = document.createElement( 'style' );
        style.type = 'text/css';
        style.innerHTML = css;
        head.appendChild( style );
    }

    //Init
    addGlobalStyle( '.media-viewer-thumbs-container { display: none; }' );
    addGlobalStyle( '.menu.menu-horizontal.media-panel-tools { display: none; }' );

    addGlobalStyle( 'div.chat.media-chat { background-color: transparent; color: white; }' );
    addGlobalStyle( 'div.chat-body { background-color: rgba(255,255,255,0.8); flex-grow: 0; padding: 8px; border-radius: 4px; }' );

    addGlobalStyle( 'div.media-panel-header { z-index: 999; background-color: transparent; }' );
    addGlobalStyle('span.media-caption { z-index: 999; background-color: white; padding: 15px; border-radius: 5px; }');

    addGlobalStyle('div.media-content { background-color: black; position: absolute; width: 100%; height: 100%; padding: 0; }');
    addGlobalStyle( '.btn-round { z-index: -1; }' );

    addGlobalStyle( 'div.media > div.object-fit > div { position: absolute; padding: 0; }' );
    addGlobalStyle( '.media-viewer .avatar { height: 120px !important; width: 120px !important; margin-top: 110px;}' );
    addGlobalStyle( '.media-viewer div.chat-body { max-height: 40px; margin-top: 110px; }' );
    addGlobalStyle( '.fadeIn {animation: fadeInOut 10s; transition: transform 5s linear; transform: scale(1.1);}' );    
    addGlobalStyle( '@keyframes fadeInOut {    0% {        opacity: 0;    }    5% {       opacity: 1;    }    45% {       opacity: 1;    }    50% {       opacity: 0;    }  100% {       opacity: 0;    }}' );    
    addGlobalStyle( '.media-viewer .avatar {border: 1px solid white; }' );


    //Init on global context
    $( document ).ready( function() {

        var uniqueImages = new Set();
        var currentImage;
        var imagePointer;
        var newImages=false;

        function getMediaParent() {
            let divMedia = $( 'div.media > div.object-fit > div' );
            if ( divMedia.length > 0 ) {
                return divMedia;
            } else {
                if ( $( 'div.media > audio' ).length > 0 ) {
                    return $( 'div.media' );
                }
            }
        }
        var imageObserver;
        function observeImages() {
            if ( imageObserver ) {
                imageObserver.disconnect();
            }

            // select the target node
            var target = $( '#app > div > span:nth-child(2)' )[ 0 ];
            // create an observer instance
            imageObserver = new MutationObserver( function( mutations ) {
                //console.log('observeImages');
                //console.log(mutations);
                var divParent = getMediaParent();
                if(divParent){
                    var h = divParent.height();
                    var w = divParent.width();
                    var mediaObj = $( divParent.children()[ 0 ] );

                    if ( mediaObj[ 0 ] ) {
                        if ( mediaObj.is( 'img' ) ) {
                            mediaObj.load( function( e ) {
                                startTimeOutNext();
                            } );
                        }

                        mediaObj[ 0 ].addEventListener( 'loadeddata', function( e ) {
                            startTimeOutNext( e.target.duration * 1000 );
                        }, false );

                        if (( mediaObj.is('img') ) || ( mediaObj.is('video') )) {

                            var src = mediaObj.attr('src');
                            currentImage = src;
                            //console.log('currentImage: ' + currentImage);
                            if(src){
                                uniqueImages.add(src);
                            }
                            //console.log('totalImages: ' + uniqueImages.size);
                            //console.log(uniqueImages);


                            if ( mediaObj.is('img') ){
                                mediaObj.addClass('fadeIn');
                            }
                            if ( w / h > 1.78 ) {
                                mediaObj.css( 'width', '100%' ).css( 'height', 'auto' );
                                divParent.css( 'width', '100%' ).css( 'height', 'auto' );
                            } else {
                                mediaObj.css( 'height', '100%' ).css( 'width', 'auto' );
                                divParent.css( 'height', '100%' ).css( 'width', 'auto' );
                            }
                        }
                    }else{
                        console.log('not image or video!? ');
                        startTimeOutNext();
                    }
                }
                // observer.disconnect();
            } );

            // configuration of the observer:
            var config = { childList: true, subtree: true };

            // pass in the target node, as well as the observer options
            imageObserver.observe( target, config );
        }

        var messagesObserver;
        function observeMessages() {
            if ( messagesObserver ) {
                messagesObserver.disconnect();
            }

            var target = $( '#main > div.pane-body.pane-chat-tile-container > div > div > div.message-list' )[ 0 ];
            messagesObserver = new MutationObserver( function( mutations ) {
                console.log('observeMessages');
                //console.log(mutations);

                let newImageMessages = searchNewImageMessages(mutations);
                if (newImageMessages.length > 0) {
                    //console.log(newImageMessages);
                    console.log('New images/videos have arrived');                    
                    newImages = true;
                    nextMedia();
                }
            } );

            // configuration of the observer:
            var config = { childList: true };

            // pass in the target node, as well as the observer options
            messagesObserver.observe( target, config );
        }

        function searchNewImageMessages (mutations) {
            return mutations.map(function (mutation) {
                console.log('map');
                return mutation.addedNodes;
            }).reduce(function (allMutations, mutationNodes) {
                console.log('reduce');
                allMutations.push(mutationNodes[0]);

                return allMutations;
                /* This is important! */
            }, []).filter(function (node) {
                console.log('filter');
                return node && node.className && node.className.indexOf('msg') > -1;
            }).map(function (node) {
                console.log('map 2');
                return node.children[1];
            }).filter(function (node) {
                console.log('filter 2');
                return node && node.className && (node.className.indexOf('message-image') > -1 || node.className.indexOf('message-video') > -1);
            });

        }

        var timeOutNext;
        function startTimeOutNext( transitionInterval ) {
            transitionInterval = transitionInterval || DEFAULT_INTERVAL;

            if ( timeOutNext ) {
                clearTimeout( timeOutNext );
            }

            timeOutNext = setTimeout( function() {
                timeOutNext = undefined;
                nextMedia();
            }, transitionInterval );
        }

        function nextMedia() {
            if ( !timeOutNext ) {
                console.log('nextMedia');
                fadeOut();


                var currImg = currentImageShown();
                if (newImages && !imagePointer) {
                    console.log('new images have arrived: store pointer');
                    imagePointer = currImg;
                }
                var src = goToNext();//normal

                if(!uniqueImages.has(src)){
                    console.log('image never shown before: do nothing: '+uniqueImages.size);                    
                }else{ 
                    if(newImages){
                        console.log('new images have arrived: go to first new image');
                        let prevSrc = null;
                        do {
                            prevSrc = src;
                            src = goToNext();
                            console.log('scroll forward to new');
                        } while (uniqueImages.has(src) && prevSrc !== src);
                        newImages = false;
                    } 
                    if (src === currImg) {
                        if(isItReallyTheEnd(src)){

                            console.log('The end: go back');
                            let prevSrc;
                            let index = uniqueImages.lenght * 2;
                            index = index < 100? 100:index;
                            while (prevSrc !== src || 0 > index--) {
                                console.log('scroll backwards to: '+imagePointer);
                                prevSrc = src;
                                src = goToPrevious();

                                if (imagePointer && imagePointer.localeCompare(src) === 0) {
                                    console.log('Previous location found: ' + imagePointer);
                                    imagePointer = undefined;
                                    goToNext();
                                    break;
                                }
                                if(prevSrc === src){
                                    console.log('The beginning?: maybe the same image is used multiple times');                        
                                    src = goToPrevious();
                                }

                            }
                            if (src === currImg) {
                                console.log('It is still stuck :(');
                                src = goToPrevious();
                                src = goToPrevious();
                            }
                        }
                    }
                }
                uniqueImages.add(src);
            }
        }

        function isItReallyTheEnd(src) {
            console.log('The end?: maybe the same image is used multiple times');                        
            let prevSrc = src;
            let index = 5;
            while (prevSrc === src && 0 < index--) {                
                prevSrc = src;
                console.log('check next');
                src = goToNext();
            }
            return prevSrc === src;
        }

        function goToNext() {
            // Send KeyDown Event
            let event = new Event('keydown');
            event.keyCode = 39; // keyright
            window.dispatchEvent(event);

            return currentImageShown();
        }


        function goToPrevious() {
            // Send KeyDown Event
            let event = new Event('keydown');
            event.keyCode = 37; // keyleft
            window.dispatchEvent(event);

            return currentImageShown();
        }

        function currentImageShown() {
            var divParent = getMediaParent();
            if (divParent && divParent.children) {
                var mediaObj = $(divParent.children()[0]);
                if (( mediaObj.is('img') ) || ( mediaObj.is('video') )) {

                    return mediaObj.attr('src');
                }
            }
            console.log('Something is not right');
            startTimeOutNext();
            return 'not found';
        }

        function fadeOut() {
            var divParent = getMediaParent();
            if (divParent && divParent.children) {
                var mediaObj = $(divParent.children()[0]);
                if (( mediaObj.is('img') ) || ( mediaObj.is('video') )) {

                    mediaObj.removeClass('fadeIn');
                }
            }
        }


        function startObservers() {
            console.log('startObservers');
            observeImages();
            observeMessages();
        }

        $( 'body' ).on( 'click', '#pane-side > div > div > div > div', startObservers );
    } );

} )( jQuery );