Recommended Posts

Recently downloaded all my posts off Facebook. I did the HMTL first which worked, but it was just a single HTML file which was a single page with all my posts. Then I downloaded the file in JSON format. I wanted to save the text of each individual post as their own file.

So with the help of ChatGPT, I had it code me this app. Which opens the Posts JSON file. and lists them all on the left. When you click it, it shows you the post text on the right. You can search at the top of keywords.

You can also export Individually checked posts or everything, each in their own TXT file to a directory of your choosing.

Not sure if anyone else will find it useful.

image.png.5ce4fe5795109d6c35f2d8544b350bf3.png

image.png.8af32f01ec1e9cf3e8f6e467ecc7d3c2.png

 

You can also sort by name

image.png.cf2dc092b07ca586044f25ffa6b44289.png

 

 

import sys
import json
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QListWidget, QTextBrowser, QVBoxLayout, QPushButton, QFileDialog, QSplitter, QLineEdit, QListWidgetItem
from PyQt5.QtGui import QFont
from PyQt5.QtCore import Qt, QSettings
import os
import re

class FacebookProfileViewer(QMainWindow):
    def __init__(self):
        super().__init__(None)
        self.setWindowTitle("Facebook Profile Viewer")
        self.setGeometry(100, 100, 800, 600)

        self.central_widget = QSplitter()
        self.setCentralWidget(self.central_widget)

        self.post_list = QListWidget()
        self.post_list.itemClicked.connect(self.display_post)

        self.post_text_browser = QTextBrowser()

        self.load_button = QPushButton("Load JSON File")
        self.load_button.clicked.connect(self.load_data)

        self.sort_button = QPushButton("Sort by Name")
        self.sort_button.clicked.connect(self.sort_by_name)

        self.search_box = QLineEdit()
        self.search_box.textChanged.connect(self.filter_articles)

        self.select_all_button = QPushButton("Select All")
        self.select_all_button.clicked.connect(self.select_all)

        self.deselect_all_button = QPushButton("Deselect All")
        self.deselect_all_button.clicked.connect(self.deselect_all)

        self.save_button = QPushButton("Save Selected")
        self.save_button.clicked.connect(self.save_selected)

        self.save_all_button = QPushButton("Save All")
        self.save_all_button.clicked.connect(self.save_all)

        self.left_widget = QWidget()
        left_layout = QVBoxLayout()
        left_layout.addWidget(self.load_button)
        left_layout.addWidget(self.sort_button)
        left_layout.addWidget(self.search_box)
        left_layout.addWidget(self.select_all_button)
        left_layout.addWidget(self.deselect_all_button)
        left_layout.addWidget(self.save_button)
        left_layout.addWidget(self.save_all_button)
        left_layout.addWidget(self.post_list)
        self.left_widget.setLayout(left_layout)

        self.central_widget.addWidget(self.left_widget)
        self.central_widget.addWidget(self.post_text_browser)

        self.data = []
        self.post_data_dict = {}
        self.filtered_articles = []

        # Initialize QSettings for storing last save location
        self.settings = QSettings("MyCompany", "MyApp")

    def load_data(self):
        options = QFileDialog.Options()
        options |= QFileDialog.ReadOnly
        last_opened_folder = self.settings.value("last_opened_folder", os.path.expanduser("~"))
        file_dialog = QFileDialog.getOpenFileName(self, "Open JSON File", last_opened_folder, "JSON Files (*.json);;All Files (*)", options=options)
        if file_dialog[0]:
            json_file = file_dialog[0]
            with open(json_file, 'r', encoding='utf-8') as file:
                self.data = json.load(file)

            self.post_list.clear()
            self.post_data_dict.clear()
            seen_paragraphs = set()
            for entry in self.data:
                if "data" in entry and entry["data"]:
                    for post in entry["data"]:
                        if "post" in post:
                            post_text = post["post"]
                            post_text = post_text.replace("\u00e2\u0080\u0099", "'")
                            post_text = post_text.replace("\u00e2\u0080\u009c", '"').replace("\u00e2\u0080\u009d", '"')
                            post_paragraph = post_text.split('\n')[0]
                            if post_paragraph not in seen_paragraphs:
                                seen_paragraphs.add(post_paragraph)
                                self.post_data_dict[post_paragraph] = post_text
                                item = QListWidgetItem(post_paragraph)
                                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
                                item.setCheckState(Qt.Unchecked)
                                self.post_list.addItem(item)
            self.filtered_articles = list(self.post_data_dict.keys())

    def display_post(self, item):
        post_paragraph = item.text()
        post_text = self.post_data_dict.get(post_paragraph, "")
        self.post_text_browser.setPlainText(post_text)
        font = QFont()
        font.setPointSize(16)
        self.post_text_browser.setFont(font)

    def sort_by_name(self):
        sorted_paragraphs = sorted(self.post_data_dict.keys())
        self.post_list.clear()
        for paragraph in sorted_paragraphs:
            item = QListWidgetItem(paragraph)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(Qt.Unchecked)
            self.post_list.addItem(item)

    def filter_articles(self):
        search_text = self.search_box.text()
        self.post_list.clear()
        for article in self.filtered_articles:
            if search_text.lower() in article.lower():
                item = QListWidgetItem(article)
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
                item.setCheckState(Qt.Unchecked)
                self.post_list.addItem(item)

    def select_all(self):
        for i in range(self.post_list.count()):
            item = self.post_list.item(i)
            item.setCheckState(Qt.Checked)

    def deselect_all(self):
        for i in range(self.post_list.count()):
            item = self.post_list.item(i)
            item.setCheckState(Qt.Unchecked)

    def sanitize_filename(self, filename):
        # Remove special characters
        sanitized_name = re.sub(r'[^\w\d]+', '_', filename)
        # Limit filename length
        return sanitized_name[:50]  # You can adjust the length as needed

    def save_selected(self):
        selected_items = [self.post_list.item(i) for i in range(self.post_list.count()) if self.post_list.item(i).checkState() == Qt.Checked]
        last_save_folder = self.settings.value("last_save_folder", os.path.expanduser("~"))
        folder_path = QFileDialog.getExistingDirectory(self, "Choose Folder to Save Files", last_save_folder)
        if folder_path:
            self.settings.setValue("last_save_folder", folder_path)  # Save the last save folder
            for item in selected_items:
                post_paragraph = item.text()
                post_text = self.post_data_dict.get(post_paragraph, "")
                if post_text:
                    # Extract the first 6 words as the file name
                    words = post_paragraph.split()[:9]
                    file_name = "_".join(words)
                    file_name = self.sanitize_filename(file_name)
                    file_name = os.path.join(folder_path, file_name + ".txt")
                    with open(file_name, 'w', encoding='utf-8') as file:
                        file.write(post_text)

    def save_all(self):
        last_save_folder = self.settings.value("last_save_folder", os.path.expanduser("~"))
        folder_path = QFileDialog.getExistingDirectory(self, "Choose Folder to Save Files", last_save_folder)
        if folder_path:
            self.settings.setValue("last_save_folder", folder_path)  # Save the last save folder
            for article, text in self.post_data_dict.items():
                sanitized_filename = self.sanitize_filename(article)
                file_path = os.path.join(folder_path, sanitized_filename + ".txt")
                with open(file_path, 'w', encoding='utf-8') as file:
                    file.write(text)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    viewer = FacebookProfileViewer()
    viewer.show()
    sys.exit(app.exec_())

 

 

  • Like 3

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • "This transition will take several years so we shouldn't bother doing it at all" is a naive take. This is completely normal for all specifications that cross-cut software, hardware and multiple industries. Look at the PCI specification for another example, consumers barely have PCI-E 5 yet PCI-SIG is working on PCI-E 8. AV2 will take multiple years to get adoption and even then, even a decade from now people will still have older hardware that doesn't support it. That's fine, because the savings still add up as newer devices add the hardware to deal with it. The goal is never to get 100% on the new spec overnight, but to gradually adopt it.
    • Firefox, and Vivaldi for the rare instances I need a Chrome based browser for a particular site.
    • I named Hitler because he is the de facto anti-semite. But you don't have to hate Jews to be a genocidal maniac. In fact, these days, so called semites are the ones acting in ways that would make Hitler proud.
    • 3DP Chip 26.05 by Razvan Serea 3DP Chip is a standalone, no-install portable tool that scans your computer’s hardware and automatically detects the latest drivers available for your specific configuration and external devices. It provides a clear list of drivers that need updates, locates the correct downloads, and helps you upgrade them easily. 3DP Chip will automatically detect and display the information on your CPU, motherboard, video card and sound card installed on your PC. You can also choose to copy these information into your clipboard with one click for later use (such as posting in a forum). Also, if you're upgrading your operating system or just need to reinstall Windows, 3DP Chip can backup all the drivers on your PC or laptop. 3DP Chip backup and reinstall features can save you hours of searching for and installing individual device drivers. 3DP Chip most popular drivers include: audio and sound drivers video drivers printer and scanner drivers digital camera drivers network drivers webcam drivers keyboard and mouse drivers 3DP Chip v26.05 changelog: Driver date/version information has been added or updated AMD motherboard chipset v8.03.25.247 AMD motherboard chipset v8.05.04.516 Newly added product or support has been enhanced AMD Radeon Graphics AMD Radeon 780M Graphics AMD Radeon 840M Graphics AMD Radeon 860M Graphics AMD Radeon 880M Graphics AMD Radeon RX 9070 XT AMD Radeon Pro W7500M NVIDIA GeForce RTX 3050 6GB Laptop GPU NVIDIA GeForce RTX 4050 Laptop GPU NVIDIA GeForce RTX 5050 Laptop GPU NVIDIA GeForce RTX 5050 Laptop GPU NVIDIA GeForce RTX 5060 NVIDIA GeForce RTX 5070 Laptop GPU NVIDIA GeForce RTX 5070 Ti Laptop GPU NVIDIA RTX Pro 500 Blackwell Generation Laptop GPU NVIDIA RTX Pro 1000 Blackwell Generation Laptop GPU NVIDIA RTX Pro 2000 Blackwell Generation Laptop GPU Download: 3DP Chip 26.05 | 7.2 MB (Freeware) Links: 3DP Chip Home Page | Screenshot Get alerted to all of our Software updates on Twitter at @NeowinSoftware
  • Recent Achievements

    • One Month Later
      nothanks earned a badge
      One Month Later
    • One Month Later
      B2Proxy earned a badge
      One Month Later
    • One Year In
      MadMung0 earned a badge
      One Year In
    • Week One Done
      jefred earned a badge
      Week One Done
    • Apprentice
      JoeyNeo went up a rank
      Apprentice
  • Popular Contributors

    1. 1
      +primortal
      472
    2. 2
      PsYcHoKiLLa
      229
    3. 3
      Skyfrog
      72
    4. 4
      FloatingFatMan
      62
    5. 5
      neufuse
      53
  • Tell a friend

    Love Neowin? Tell a friend!