File size: 8,246 Bytes
478b861
6236d6b
 
 
 
6f8030b
64e4dd7
6f8030b
478b861
 
 
6236d6b
 
478b861
 
6236d6b
 
 
 
478b861
6236d6b
 
 
 
 
 
 
478b861
6236d6b
68e6e0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64e4dd7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8f4a78c
64e4dd7
 
 
 
 
 
 
 
 
478b861
64e4dd7
6236d6b
478b861
 
 
 
 
6236d6b
 
 
478b861
 
6236d6b
 
 
 
 
478b861
8df5ef2
6236d6b
478b861
6236d6b
478b861
6236d6b
 
 
478b861
 
 
6236d6b
 
 
 
 
6f8030b
 
8df5ef2
6236d6b
6f8030b
 
6236d6b
 
 
 
 
 
 
 
 
 
68e6e0a
 
 
478b861
6236d6b
8df5ef2
6236d6b
 
 
 
 
 
 
 
 
2adbbaf
68e6e0a
8df5ef2
478b861
6236d6b
 
478b861
6236d6b
 
8df5ef2
 
68e6e0a
 
 
 
 
 
 
478b861
 
 
8df5ef2
478b861
68e6e0a
 
 
 
 
6236d6b
 
 
 
 
 
 
 
 
478b861
 
 
6236d6b
478b861
 
 
 
 
 
 
 
2adbbaf
 
 
 
 
478b861
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import gradio as gr
from huggingface_hub import HfApi
from huggingface_hub.utils import HfHubHTTPError

# --- Core Functions ---
# Don't pause or privatize this_space
this_space="broadfield-dev/HF-privatize"

def get_my_spaces(hf_token):
    """Fetches a list of the user's public Hugging Face Spaces."""
    if not hf_token:
        # Return empty values for all outputs
        return [], "Please enter your Hugging Face token.", []
    try:
        api = HfApi(token=hf_token)
        # Get the username to list spaces accurately
        username = api.whoami()["name"]
        spaces = api.list_spaces(author=username)
        # Filter for only public spaces
        public_spaces = [space.id for space in spaces if not space.private]
        if not public_spaces:
            return [], "Successfully connected, but you have no public spaces.", []
        # Return the list of spaces for the checkboxes and the state
        return public_spaces, f"Successfully listed {len(public_spaces)} public spaces.", public_spaces
    except HfHubHTTPError as e:
        # Handle common authentication errors
        return [], f"Authentication error: Please check your token. Details: {e}", []
    except Exception as e:
        return [], f"An error occurred: {e}", []
        
def get_my_spaces_all(hf_token):
    """Fetches a list of the user's public Hugging Face Spaces."""
    if not hf_token:
        # Return empty values for all outputs
        return [], "Please enter your Hugging Face token.", []
    try:
        api = HfApi(token=hf_token)
        # Get the username to list spaces accurately
        username = api.whoami()["name"]
        spaces = api.list_spaces(author=username)
        # Filter for only public spaces
        public_spaces = [space.id for space in spaces]
        if not public_spaces:
            return [], "Successfully connected, but you have no public spaces.", []
        # Return the list of spaces for the checkboxes and the state
        return public_spaces, f"Successfully listed {len(public_spaces)} public spaces.", public_spaces
    except HfHubHTTPError as e:
        # Handle common authentication errors
        return [], f"Authentication error: Please check your token. Details: {e}", []
    except Exception as e:
        return [], f"An error occurred: {e}", []
        
def make_spaces_paused(hf_token, selected_spaces, progress=gr.Progress()):
    """Sets the visibility of selected Hugging Face Spaces to private."""
    if not hf_token:
        return "Please enter your Hugging Face token."
    if not selected_spaces:
        return "Please select at least one space to Pause."
    
    progress(0, desc="Starting...")
    
    try:
        api = HfApi(token=hf_token)
        log_messages = []
        total_spaces = len(selected_spaces)

        for i, space_id in enumerate(selected_spaces):
            progress((i + 1) / total_spaces, desc=f"Processing '{space_id}'...")
            try:
                if not space_id == this_space:
                    api.pause_space(repo_id=space_id)
                    log_messages.append(f"βœ… Successfully made '{space_id}' paused.")
            except Exception as e:
                log_messages.append(f"❌ Failed to make '{space_id}' paused: {e}")
        
        return "\n".join(log_messages)
    except HfHubHTTPError as e:
        return f"Authentication error: Please check your token. Details: {e}"
    except Exception as e:
        return f"An error occurred: {e}"

        
def make_spaces_private(hf_token, selected_spaces, progress=gr.Progress()):
    """Sets the visibility of selected Hugging Face Spaces to private."""
    if not hf_token:
        return "Please enter your Hugging Face token."
    if not selected_spaces:
        return "Please select at least one space to make private."
    
    progress(0, desc="Starting...")
    
    try:
        api = HfApi(token=hf_token)
        log_messages = []
        total_spaces = len(selected_spaces)

        for i, space_id in enumerate(selected_spaces):
            progress((i + 1) / total_spaces, desc=f"Processing '{space_id}'...")
            try:
                api.update_repo_settings(repo_id=space_id, private=True, repo_type="space")
                log_messages.append(f"βœ… Successfully made '{space_id}' private.")
            except Exception as e:
                log_messages.append(f"❌ Failed to make '{space_id}' private: {e}")
        
        return "\n".join(log_messages)
    except HfHubHTTPError as e:
        return f"Authentication error: Please check your token. Details: {e}"
    except Exception as e:
        return f"An error occurred: {e}"

# --- Gradio UI ---

with gr.Blocks(theme=gr.themes.Soft()) as demo:
    gr.Markdown(
        """
        # πŸ›‘οΈ Hugging Face Space Privacy & Pause Control
        Quickly make your public Hugging Face Spaces private and paused.
        1.  Create and paste a Hugging Face access token with **write** permission.
        2.  Click "List My Public Spaces".
        3.  Select the spaces you want to make private or paused (or use "Select All").
        4.  Click the final button to update their settings.
        """
    )

    with gr.Row():
        hf_token_input = gr.Textbox(
            label="Hugging Face Write Token",
            type="password",
            placeholder="hf_...",
            scale=3,
        )
        with gr.Column():
            list_spaces_button = gr.Button("List My Public Spaces", variant="secondary", scale=1)
            list_spaces_button_all = gr.Button("List All My Spaces", variant="secondary", scale=1)
    
    with gr.Group():
        # This (invisible) state component is the key to the select_all fix
        spaces_list_state = gr.State([])

        select_all_checkbox = gr.Checkbox(label="Select All / Deselect All")
        
        spaces_checkboxes = gr.CheckboxGroup(
            label="Your Public Spaces",
            info="Only your public spaces are shown here."
        )

    make_private_button = gr.Button("Set Selected Spaces Private", variant="primary")
    make_paused_button = gr.Button("Set Selected Spaces Paused", variant="primary")
    status_output = gr.Textbox(label="Status", interactive=False, lines=5)

    # --- Event Listeners ---

    def list_spaces_action(token):
        """Called when the list button is clicked. Updates the checkboxes and the state."""
        spaces, message, state_list = get_my_spaces(token)
        # Also reset the select_all checkbox to unchecked
        return gr.update(choices=spaces, value=[]), message, state_list, gr.update(value=False)
        
    def list_spaces_action_all(token):
        """Called when the list button is clicked. Updates the checkboxes and the state."""
        spaces, message, state_list = get_my_spaces_all(token)
        # Also reset the select_all checkbox to unchecked
        return gr.update(choices=spaces, value=[]), message, state_list, gr.update(value=False)
        
    list_spaces_button.click(
        fn=list_spaces_action,
        inputs=hf_token_input,
        outputs=[spaces_checkboxes, status_output, spaces_list_state, select_all_checkbox]
    )
    list_spaces_button_all.click(
        fn=list_spaces_action_all,
        inputs=hf_token_input,
        outputs=[spaces_checkboxes, status_output, spaces_list_state, select_all_checkbox]
    )
    def select_all_action(select_all_checked, full_list_of_spaces):
        """
        Called when the "Select All" checkbox is changed.
        Uses the list from the state to update the checkbox group.
        """
        if select_all_checked:
            return gr.update(value=full_list_of_spaces)  # Select all
        else:
            return gr.update(value=[])  # Deselect all

    select_all_checkbox.change(
        fn=select_all_action,
        inputs=[select_all_checkbox, spaces_list_state], # Input is from the state now
        outputs=spaces_checkboxes
    )

    make_private_button.click(
        fn=make_spaces_private,
        inputs=[hf_token_input, spaces_checkboxes],
        outputs=status_output
    )
    make_paused_button.click(
        fn=make_spaces_paused,
        inputs=[hf_token_input, spaces_checkboxes],
        outputs=status_output
    )
demo.launch()