• Login
  • Register
  • Login Register
    Login
    Username/Email:
    Password:
    Or login with a social network below
  • Forum
  • Website
  • GitHub
  • Status
  • Translation
  • Features
  • Team
  • Rules
  • Help
  • Feeds
User Links
  • Login
  • Register
  • Login Register
    Login
    Username/Email:
    Password:
    Or login with a social network below

    Useful Links Forum Website GitHub Status Translation Features Team Rules Help Feeds
    Jellyfin Forum Development Web Development Jellyfin UI Enhancements

     
    • 0 Vote(s) - 0 Average

    Jellyfin UI Enhancements

    Injecting pages or code into jellyfin-web for pseudo-plugin functionality
    M0RPH3US
    Offline

    Member

    Posts: 89
    Threads: 5
    Joined: 2023 Jun
    Reputation: 7
    #4
    2024-10-29, 05:27 PM (This post was last modified: 2024-10-29, 06:07 PM by TheDreadPirate. Edited 2 times in total.)
    (2024-10-28, 08:02 PM)SethBacon Wrote: Some example functions. Note: for a lot of media manipulation you will want to generate an api code in jellyfin Admin settings, thenm hardcode it into your injections to make api calls. 

    Code:
    // Get the current authenticated user's info
    const getCurrentUser = () => {
        return fetch('/Users/Me', {
            method: 'GET',
            headers: {
                'Authorization': `MediaBrowser Token="${ApiClient.accessToken()}"`,
                'Content-Type': 'application/json'
            }
        })
        .then(response => response.json())
        .catch(error => {
            console.error('Error getting current user:', error);
            return null;
        });
    };

    // Get a user's profile image URL by their ID
    const getUserImageUrl = (userId) => {
        return `${ApiClient.serverAddress()}/Users/${userId}/Images/Primary?quality=90`;
    };

    // Update a media item's tags
    const updateMediaTags = (itemId, newTags) => {
        return ApiClient.getItem(ApiClient.getCurrentUserId(), itemId)
            .then(item => {
                const updatedTags = [...new Set([...item.Tags, ...newTags])];
                return ApiClient.updateItem({
                    Id: itemId,
                    Tags: updatedTags
                });
            })
            .catch(error => {
                console.error('Error updating tags:', error);
                return false;
            });
    };

    // Watch for navigation changes in Jellyfin's SPA
    const watchNavigation = (callback) => {
        const observer = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                if (mutation.type === 'childList' &&
                    mutation.target.classList.contains('view')) {
                    callback(window.location.hash);
                }
            });
        });
       
        observer.observe(document.querySelector('div[data-role="content"]'), {
            childList: true,
            subtree: true
        });
       
        return observer;
    };

    // Inject a custom element into a specific page section
    const injectElement = (targetSelector, htmlContent, position = 'beforeend') => {
        const target = document.querySelector(targetSelector);
        if (target) {
            target.insertAdjacentHTML(position, htmlContent);
            return true;
        }
        return false;
    };

    // Get all users and their online status
    const getOnlineUsers = () => {
        return fetch('/Users/Query', {
            method: 'GET',
            headers: {
                'Authorization': `MediaBrowser Token="${ApiClient.accessToken()}"`,
                'Content-Type': 'application/json'
            }
        })
        .then(response => response.json())
        .then(users => {
            return ApiClient.getSessions()
                .then(sessions => {
                    return users.map(user => ({
                        ...user,
                        isOnline: sessions.some(session => session.UserId === user.Id)
                    }));
                });
        })
        .catch(error => {
            console.error('Error getting online users:', error);
            return [];
        });
    };

    // Add a custom button to the media details page
    const addCustomButton = (text, onClick) => {
        const buttonHtml = `
            <button is="emby-button"
                    type="button"
                    class="button-flat btnPlay button-flat-custom raised">
                <span>${text}</span>
            </button>
        `;
       
        injectElement('.detailButtons', buttonHtml);
       
        const button = document.querySelector('.button-flat-custom');
        if (button) {
            button.addEventListener('click', onClick);
        }
    };

    // Watch for theme changes and apply custom styles
    const watchThemeChanges = (callback) => {
        const observer = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                if (mutation.attributeName === 'data-theme') {
                    const theme = document.documentElement.getAttribute('data-theme');
                    callback(theme);
                }
            });
        });
       
        observer.observe(document.documentElement, {
            attributes: true,
            attributeFilter: ['data-theme']
        });
       
        return observer;
    };
    // Example usage of the functions:
    /*
    // Watch for navigation changes
    const navObserver = watchNavigation((newPath) => {
        console.log('Navigation changed to:', newPath);
        if (newPath.includes('details')) {
            addCustomButton('My Custom Action', () => {
                console.log('Custom button clicked!');
            });
        }
    });

    // Watch for theme changes
    const themeObserver = watchThemeChanges((newTheme) => {
        console.log('Theme changed to:', newTheme);
        // Apply custom styles based on theme
    });

    // Get current user and update UI
    async function updateUserInfo() {
        const user = await getCurrentUser();
        if (user) {
            const userImage = getUserImageUrl(user.Id);
            console.log('Current user:', user.Name);
            console.log('User image:', userImage);
        }
    }

    // Update media tags
    async function addTagToMedia(itemId, newTag) {
        const success = await updateMediaTags(itemId, [newTag]);
        if (success) {
            console.log('Tags updated successfully');
        }
    }

    // Check online users
    async function showOnlineUsers() {
        const users = await getOnlineUsers();
        users.forEach(user => {
            console.log(`${user.Name} is ${user.isOnline ? 'online' : 'offline'}`);
        });
    }
    */

    Oh that looks sick. I have a custom varient of my bar which yet I didnot release as public (it's there on Bob's repo as the makd version, I have some local tweaks which I will do a public release once I get my head around), but to tackle the SPA issue, we can kind of prevent the default behaviour for all buttons (header bar home, hamburger menu home, and the jellylogo at the top of the dashboard) to route it to 
    Code:
    window.location.href = '/web/index.html#/home.html
    then we can circumnavigate that issue. I am caught up with office, but can catch up with you guys to share what I have.

    But @SethBacon and @Ted Hinklater for sure, look forward really to Collab for the bar again
    « Next Oldest | Next Newest »

    Users browsing this thread: 2 Guest(s)


    Messages In This Thread
    Jellyfin UI Enhancements - by SethBacon - 2024-10-28, 07:57 PM
    RE: Jellyfin UI Enhancements - by SethBacon - 2024-10-28, 08:02 PM
    RE: Jellyfin UI Enhancements - by M0RPH3US - 2024-10-29, 05:27 PM
    RE: Jellyfin UI Enhancements - by Ted Hinklater - 2024-10-29, 04:48 PM
    RE: Jellyfin UI Enhancements - by TheDreadPirate - 2024-10-29, 06:07 PM
    RE: Jellyfin UI Enhancements - by Valentin - 2024-10-31, 10:24 AM
    RE: Jellyfin UI Enhancements - by locoboco - 2024-12-30, 08:27 AM
    RE: Jellyfin UI Enhancements - by OneMeanRabbit - 2025-04-08, 08:14 AM
    RE: Jellyfin UI Enhancements - by JellyHunter - 2025-04-21, 08:48 PM

    • View a Printable Version
    • Subscribe to this thread
    Forum Jump:

    Home · Team · Help · Contact
    © Designed by D&D - Powered by MyBB
    L


    Jellyfin

    The Free Software Media System

    Linear Mode
    Threaded Mode