Guest User

Untitled

a guest
Oct 30th, 2024
38
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.90 KB | None | 0 0
  1. import json
  2. from typing import Dict, List
  3. import html
  4. from datetime import datetime
  5. import subprocess
  6. import os
  7.  
  8. """
  9. instructions to add a category
  10. 1. add the table header
  11. 2. add the table defenition and change the data class to what you want
  12. 3. add the json cateogry and make it the exact same as the data class. dont forget the trailing comma
  13. """
  14.  
  15. def parse_twitter_user(entry: Dict) -> Dict:
  16.     """Extract relevant user information from a Twitter API entry."""
  17.     try:
  18.         user_data = entry.get("content", {}).get("itemContent", {}).get("user_results", {}).get("result", {})
  19.         if not user_data or not user_data.get("legacy"):
  20.             print(f"Warning: Invalid user data structure: {entry}")
  21.             return None
  22.            
  23.         legacy = user_data["legacy"]
  24.        
  25.         return {
  26.             "profile_image": legacy.get("profile_image_url_https", ""),
  27.             "screen_name": legacy.get("screen_name", ""),
  28.             "name": html.escape(legacy.get("name", "")),
  29.             "description": html.escape(legacy.get("description", "")),
  30.             "following": legacy.get("friends_count", 0),
  31.             "followers": legacy.get("followers_count", 0),
  32.             "location": html.escape(legacy.get("location", "")),
  33.             "follows_you": legacy.get("followed_by", False)
  34.         }
  35.     except Exception as e:
  36.         print(f"Error parsing user data: {e}")
  37.         return None
  38.  
  39. def generate_html(users: List[Dict]) -> str:
  40.     """Generate HTML page with Twitter following table."""
  41.     users = [user for user in users if user is not None]
  42.    
  43.     if not users:
  44.         return "<h1>No valid user data found</h1>"
  45.    
  46.     html_head = """
  47. <!DOCTYPE html>
  48. <html lang="en">
  49. <head>
  50.    <meta charset="UTF-8">
  51.    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  52.    <title>Twitter Following Management</title>
  53.    <style>
  54.        body {
  55.            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  56.            margin: 0;
  57.            background: #f7f9fa;
  58.            display: flex;
  59.            justify-content: center;
  60.            min-height: 100vh;
  61.        }
  62.        .container {
  63.            width: 95%;
  64.            padding: 20px;
  65.        }
  66.        table {
  67.            width: 100%;
  68.            border-collapse: collapse;
  69.            background: white;
  70.            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  71.            border-radius: 8px;
  72.            overflow: hidden;
  73.        }
  74.        th, td {
  75.            padding: 12px;
  76.            text-align: left;
  77.            border-bottom: 1px solid #eee;
  78.            position: relative;
  79.        }
  80.        th {
  81.            background: #1DA1F2;
  82.            color: white;
  83.            font-weight: 500;
  84.        }
  85.        .clickable {
  86.            cursor: pointer;
  87.            padding: 2px !important;
  88.        }
  89.        /* Remove the previous hover effect */
  90.        .clickable:hover {
  91.            background-color: transparent;
  92.        }
  93.        /* Add column highlighting */
  94.        td[class*="checkbox-column"],
  95.        th[class*="checkbox-column"] {
  96.            position: relative;
  97.        }
  98.        /* Create the column highlight effect */
  99.        td[class*="checkbox-column"]:hover::after,
  100.        th[class*="checkbox-column"]:hover::after,
  101.        td[class*="checkbox-column"]:hover ~ td[class*="checkbox-column"]::after,
  102.        th[class*="checkbox-column"]:hover ~ td[class*="checkbox-column"]::after {
  103.            content: '';
  104.            position: absolute;
  105.            background-color: #f8f8f8;
  106.            width: 100%;
  107.            height: 100000px;  /* Very large height to ensure coverage */
  108.            left: 0;
  109.            top: -50000px;  /* Negative offset to center the highlight */
  110.            z-index: -1;
  111.            pointer-events: none;
  112.        }
  113.        th:first-child, td:first-child {
  114.            position: sticky;
  115.            left: 0;
  116.            background-color: #f8f8f8;
  117.            z-index: 2;
  118.            background: #1DA1F2;
  119.            font-weight: 500;
  120.            box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.4);
  121.        }
  122.        thead {
  123.            position: sticky;
  124.            top: 0;
  125.            background-color: white;
  126.            z-index: 1000;
  127.            box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.4);
  128.        }
  129.        .profile-img {
  130.            width: 48px;
  131.            height: 48px;
  132.            border-radius: 50%;
  133.            vertical-align: middle;
  134.        }
  135.        .user-info {
  136.            display: flex;
  137.            align-items: center;
  138.            gap: 12px;
  139.        }
  140.        .names {
  141.            display: flex;
  142.            flex-direction: column;
  143.        }
  144.        .display-name {
  145.            font-weight: 600;
  146.        }
  147.        .username {
  148.            color: #536471;
  149.            text-decoration: none;
  150.        }
  151.        .username:hover {
  152.            text-decoration: underline;
  153.        }
  154.        .description {
  155.            color: #536471;
  156.            max-width: 300px;
  157.        }
  158.        .stats {
  159.            color: #536471;
  160.        }
  161.        .location {
  162.            color: #536471;
  163.        }
  164.        .checkbox-wrapper {
  165.            display: flex;
  166.            justify-content: center;
  167.        }
  168.        input[type="checkbox"] {
  169.            width: 20px;
  170.            height: 20px;
  171.            cursor: pointer;
  172.        }
  173.        tr:hover {
  174.            background: #f7f9fa;
  175.        }
  176.        .follows-you {
  177.            color: #1DA1F2;
  178.            text-align: center;
  179.            font-size: 18px;
  180.        }
  181.        .checkbox-column {
  182.            padding: 2px;
  183.        }
  184.    </style>
  185. </head>
  186. """
  187.  
  188.     html_body = """
  189. <body>
  190.    <div class="container">
  191.        <h1>Twitter Following Management</h1>
  192.        <p>Total Following: {total_users}</p>
  193.        <table id="following-table">
  194.            <thead>
  195.                <tr>
  196.                    <th>Count</th>
  197.                    <th>Profile</th>
  198.                    <th>Description</th>
  199.                    <th>Stats</th>
  200.                    <th>Follows You</th>
  201.                    <th>Location</th>
  202.                    <th class="checkbox-column">Unfollow</th>
  203.                    <th class="checkbox-column">AI Companies</th>
  204.                    <th class="checkbox-column">AI People</th>
  205.                    <th class="checkbox-column">Anon Coders</th>
  206.                    <th class="checkbox-column">Named Coders</th>
  207.                    <th class="checkbox-column">Investors</th>
  208.                    <th class="checkbox-column">Meme Pages</th>
  209.                    <th class="checkbox-column">Founders</th>
  210.                    <th class="checkbox-column">Design</th>
  211.                    <th class="checkbox-column">Companies</th>                    
  212.                </tr>
  213.            </thead>
  214.            <tbody>
  215.                {table_rows}"""
  216.                
  217.     html_tail = """
  218. <script>
  219.    // Function to handle checkbox state and storage
  220.    function handleCheckboxChange(checkbox) {
  221.        const screenName = checkbox.getAttribute('data-screen-name');
  222.        const category = checkbox.getAttribute('data-type');
  223.        const storageKey = `${screenName}_${category}`;
  224.        localStorage.setItem(storageKey, checkbox.checked);
  225.    }
  226.  
  227.    // Initialize all checkboxes
  228.    document.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
  229.        const screenName = checkbox.getAttribute('data-screen-name');
  230.        const category = checkbox.getAttribute('data-type');
  231.        const storageKey = `${screenName}_${category}`;
  232.        
  233.        // Load saved state
  234.        checkbox.checked = localStorage.getItem(storageKey) === 'true';
  235.        
  236.        // Add change listener
  237.        checkbox.addEventListener('change', () => handleCheckboxChange(checkbox));
  238.    });
  239.  
  240.    // Handle clicks on the entire cell
  241.    document.querySelectorAll('.clickable').forEach(td => {
  242.        td.addEventListener('click', (event) => {
  243.            // Only toggle if the click wasn't directly on the checkbox
  244.            if (event.target.type !== 'checkbox') {
  245.                const checkbox = td.querySelector('input[type="checkbox"]');
  246.                checkbox.checked = !checkbox.checked;
  247.                handleCheckboxChange(checkbox);
  248.            }
  249.        });
  250.    });
  251.  
  252.    // Add export button
  253.    const exportButton = document.createElement('button');
  254.    exportButton.textContent = 'Export Categories';
  255.    exportButton.style.cssText = 'position: fixed; bottom: 20px; right: 20px; padding: 10px 20px; background: #1DA1F2; color: white; border: none; border-radius: 4px; cursor: pointer;';
  256.    document.body.appendChild(exportButton);
  257.  
  258.    exportButton.addEventListener('click', () => {
  259.        const categories = {
  260.            'unfollow': [],
  261.            'ai companies': [],
  262.            'ai people': [],
  263.            'anon coders': [],
  264.            'named coders': [],
  265.            'investors': [],
  266.            'meme pages': [],
  267.            'founders': [],
  268.            'design': [],
  269.            'companies': []
  270.        };
  271.  
  272.        document.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
  273.            const screenName = checkbox.getAttribute('data-screen-name');
  274.            const category = checkbox.getAttribute('data-type');
  275.            if (checkbox.checked) {
  276.                categories[category].push(screenName);
  277.            }
  278.        });
  279.  
  280.        const jsonString = JSON.stringify(categories, null, 2);
  281.        const blob = new Blob([jsonString], { type: 'application/json' });
  282.        const url = URL.createObjectURL(blob);
  283.        const a = document.createElement('a');
  284.        a.href = url;
  285.        a.download = 'twitter_categories.json';
  286.        document.body.appendChild(a);
  287.        a.click();
  288.        document.body.removeChild(a);
  289.        URL.revokeObjectURL(url);
  290.        console.log(jsonString);
  291.    });
  292. </script>
  293.            </tbody>
  294.        </table>
  295.    </div>
  296. </body>
  297. </html>
  298. """
  299.  
  300.     row_template = """
  301.                <tr>
  302.                    <td style="background-color: lightgray">
  303.                        <div>{count}</div>
  304.                    </td>
  305.                    <td>
  306.                        <div class="user-info">
  307.                            <img src="{profile_image}" alt="{screen_name}" class="profile-img">
  308.                            <div class="names">
  309.                                <span class="display-name">{name}</span>
  310.                                <a href="https://twitter.com/{screen_name}" target="_blank" class="username">@{screen_name}</a>
  311.                            </div>
  312.                        </div>
  313.                    </td>
  314.                    <td class="description">{description}</td>
  315.                    <td class="stats">
  316.                        <div>Following: {following}</div>
  317.                        <div>Followers: {followers}</div>
  318.                    </td>
  319.                    <td class="stats"
  320.                        <div>{follows_you}</div>
  321.                    </td>
  322.                    <td class="location">
  323.                        {location}
  324.                    </td>
  325.                    <td class="clickable checkbox-column">
  326.                        <input type="checkbox" data-screen-name="{screen_name}" data-type="unfollow">
  327.                    </td>
  328.                    <td class="clickable checkbox-column">
  329.                        <input type="checkbox" data-screen-name="{screen_name}" data-type="ai companies">
  330.                    </td>
  331.                    <td class="clickable checkbox-column">
  332.                        <input type="checkbox" data-screen-name="{screen_name}" data-type="ai people">
  333.                    </td>                    
  334.                    <td class="clickable checkbox-column">
  335.                        <input type="checkbox" data-screen-name="{screen_name}" data-type="anon coders">
  336.                    </td>
  337.                    <td class="clickable checkbox-column">
  338.                        <input type="checkbox" data-screen-name="{screen_name}" data-type="named coders">
  339.                    </td>
  340.                    <td class="clickable checkbox-column">
  341.                        <input type="checkbox" data-screen-name="{screen_name}" data-type="investors">
  342.                    </td>      
  343.                    <td class="clickable checkbox-column">
  344.                        <input type="checkbox" data-screen-name="{screen_name}" data-type="meme pages">
  345.                    </td>    
  346.                    <td class="clickable checkbox-column">
  347.                        <input type="checkbox" data-screen-name="{screen_name}" data-type="founders">
  348.                    </td>
  349.                    <td class="clickable checkbox-column">
  350.                        <input type="checkbox" data-screen-name="{screen_name}" data-type="design">
  351.                    <td class="clickable checkbox-column">
  352.                        <input type="checkbox" data-screen-name="{screen_name}" data-type="companies">
  353.                    </td>                    
  354.                </tr>"""
  355.  
  356.     # Generate table rows
  357.     table_rows = []
  358.     for c, user in enumerate(users):
  359.         c += 1
  360.         follows_you_text = "✓" if user["follows_you"] else ""
  361.         location_text = user["location"] if user["location"] else ""
  362.        
  363.         row_html = row_template.format(
  364.             count = str(c),
  365.             profile_image=user["profile_image"],
  366.             screen_name=user["screen_name"],
  367.             name=user["name"],
  368.             description=user["description"],
  369.             following=user["following"],
  370.             followers=user["followers"],
  371.             follows_you=follows_you_text,
  372.             location=location_text
  373.         )
  374.         table_rows.append(row_html)
  375.    
  376.     # Generate final HTML
  377.     return html_head + html_body.format(
  378.         table_rows="\n".join(table_rows),
  379.         total_users=len(users)
  380.     ) + html_tail
  381.  
  382. def main():
  383.     file_name = input('what is the name of the file? ')
  384.  
  385.     users = []
  386.  
  387.     # Read and parse input JSON
  388.     with open(file_name, 'r') as f:
  389.         for c, line in enumerate(f):
  390.             print(c)
  391.             line = json.loads(line)
  392.             try:
  393.                 entries = line["data"]["user"]["result"]["timeline"]["timeline"]["instructions"][0]["entries"]
  394.             except (IndexError, KeyError, json.JSONDecodeError) as e:
  395.                 entries = line["data"]["user"]["result"]["timeline"]["timeline"]["instructions"][2]["entries"]
  396.             print(type(entries))
  397.             users.extend([parse_twitter_user(entry) for entry in entries[:-2]])  # Excluding last two entries
  398.  
  399.     # Generate HTML
  400.     html_output = generate_html(users)
  401.    
  402.     # Write to file
  403.     file_name = os.path.join('twitter_following_html', f'twitter_following_{datetime.now().isoformat()[:-7]}.html')
  404.     with open(file_name, 'w', encoding='utf-8') as f:
  405.         f.write(html_output)
  406.        
  407.     subprocess.run(['firefox', file_name])
  408.  
  409. if __name__ == "__main__":
  410.     main()
Advertisement
Add Comment
Please, Sign In to add comment